Things used in this project

Hardware components:
Microsoft Xbox Controller and Wireless Adapter for Windows
This controller can be added to a Windows PC using the adapter
×1
12577 01
SparkFun SparkFun Bluetooth Modem - BlueSMiRF Silver
Or an identical (HC-05, HC-06) Bluetooth module
×1
A000066 iso both
Arduino Arduino UNO & Genuino UNO
×1
Software apps and online services:
10
Microsoft Windows 10 IoT Core
This app is the intermediate between the standard Firmata sketch and the Xbox One controller

Code

Xaml controls to start the communicationsnippets
Paste this into the main form of your new UWP app
<StackPanel Orientation="Vertical">
  <Button Name="btnStart"
          Click="btnStart_Click"
          FontSize="50"
          Width="400"
          Content="Start" />
  <Button Name="btnController"
          Content="Controller"
          FontSize ="50"
          Width="400"
          IsEnabled="False"
          Click="btnController_Click" />
  <TextBlock Name="tbRead"
             FontSize="20"
             Foreground="Gray" />
</StackPanel>
Code-Behind of the the UWP app mainformC#
This code connects to the rover using Firmata and passes Xbox One Controller commands
public sealed partial class MainPage : Page
{
  private BluetoothSerial _bluetooth;
  private RemoteDevice _arduino;

  private UwpFirmata _firmata = null;
  private Gamepad _Gamepad = null;
  // We never supply a PWM of more then 255 * 0,75
  private double _SpeedLimit = 0.75;
  // values below this absolte value stop the rover
  private double _ActionPoint = 0.15;

  private byte _LeftForward = 6;
  private byte _LeftBackward = 7;
  private byte _LeftValue = 5;
  private byte _RightForward = 9;
  private byte _RightBackward = 8;
  private byte _RightValue = 10;

  private Dictionary<byte, PinState> _CurrentPinStates 
                           = new Dictionary<byte, PinState>();

  private Dictionary<byte, ushort> _CurrentSpeedValues 
                             = new Dictionary<byte, ushort>();

  public MainPage()
  {
    this.InitializeComponent();
  }

  private void btnStart_Click(object sender, 
                               RoutedEventArgs e)
  {
    btnStart.IsEnabled = false;

    Gamepad.GamepadAdded += Gamepad_GamepadAdded;
    Gamepad.GamepadRemoved += Gamepad_GamepadRemoved;

    _bluetooth = new BluetoothSerial("HC-06");
    _bluetooth.ConnectionLost += BluetoothConnectionLost;
    _bluetooth.ConnectionFailed += BluetoothConnectionFailed;
    _bluetooth.ConnectionEstablished += 
                                   OnConnectionEstablished;

    _firmata = new UwpFirmata();
    _arduino = new RemoteDevice(_firmata);
    _firmata.begin(_bluetooth);

    _bluetooth.begin(9600, SerialConfig.SERIAL_8N1);

    _arduino.DeviceReady += ArduinoDeviceReady;
  }

  private async void BluetoothConnectionLost(string message)
  {
    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, () =>
      {
        tbRead.Text = "ConnectionLost" + message;
        btnStart.IsEnabled = true;
      });
  }

  private async void BluetoothConnectionFailed(string message)
  {
    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, () =>
      {
        tbRead.Text = "ConnectionFailed" + message;
        btnStart.IsEnabled = true;
      });
  }

  private async void ArduinoDeviceReady()
  {
    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, () =>
      {
        tbRead.Text = "Device Ready";
      });
  }

  private void OnConnectionEstablished()
  {
    var action = Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, 
      new DispatchedHandler(() =>
      {
        DisableEnableButtons(true);

        ArduinoDigitalWrite(_LeftForward, PinState.LOW);
        ArduinoDigitalWrite(_LeftBackward, PinState.LOW);
        ArduinoDigitalWrite(_RightBackward, PinState.LOW);
        ArduinoDigitalWrite(_RightForward, PinState.LOW);
      }));
  }

  private void DisableEnableButtons(bool enabled)
  {
    // Disable all buttons. Otherwise 
    //  the 'A' will press the one focussed.
    btnController.IsEnabled = enabled;
    btnStart.IsEnabled = enabled;
  }

  private async void Gamepad_GamepadRemoved(
                                   object sender, Gamepad e)
  {
    _Gamepad = null;

    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, () =>
      {
        tbRead.Text = "Controller removed";
      });
  }
  
  private async void Gamepad_GamepadAdded(
                                   object sender, Gamepad e)
  {
    _Gamepad = e;

    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, () =>
      {
        tbRead.Text = "Controller added";
      });
  }

  private async void btnController_Click(object sender, 
                                          RoutedEventArgs e)
  {
    DisableEnableButtons(false);

    while (true)
    {
      await Task.Delay(TimeSpan.FromMilliseconds(3));

      if (_Gamepad == null)
      {
        continue;
      }

      // Get the current state
      var reading = _Gamepad.GetCurrentReading();

      if (Math.Abs(reading.LeftThumbstickY) < _ActionPoint)
      {
        ArduinoDigitalWrite(_LeftForward, PinState.LOW);
        ArduinoDigitalWrite(_LeftBackward, PinState.LOW);
        sldrLeftSpeed.Value = 0;
      }
      else if (reading.LeftThumbstickY >= _ActionPoint)
      {
        ArduinoDigitalWrite(_LeftForward, PinState.HIGH);
        ArduinoDigitalWrite(_LeftBackward, PinState.LOW);
        sldrLeftSpeed.Value = 255 * 
               Math.Abs(reading.LeftThumbstickY) * _SpeedLimit;
      }
      else if (reading.LeftThumbstickY <= -_ActionPoint)
      {
        ArduinoDigitalWrite(_LeftForward, PinState.LOW);
        ArduinoDigitalWrite(_LeftBackward, PinState.HIGH);
        sldrLeftSpeed.Value = 255 * 
               Math.Abs(reading.LeftThumbstickY) * _SpeedLimit;
      }

      if (Math.Abs(reading.RightThumbstickY) < _ActionPoint)
      {
        ArduinoDigitalWrite(_RightForward, PinState.LOW);
        ArduinoDigitalWrite(_RightBackward, PinState.LOW);
        sldrRightSpeed.Value = 0;
      }
      else if (reading.RightThumbstickY >= _ActionPoint)
      {
        ArduinoDigitalWrite(_RightForward, PinState.HIGH);
        ArduinoDigitalWrite(_RightBackward, PinState.LOW);
        sldrRightSpeed.Value = 255 * 
          Math.Abs(reading.RightThumbstickY) * _SpeedLimit;
      }
      else if (reading.RightThumbstickY <= -_ActionPoint)
      {
        ArduinoDigitalWrite(_RightForward, PinState.LOW);
        ArduinoDigitalWrite(_RightBackward, PinState.HIGH);
        sldrRightSpeed.Value = 255 * 
          Math.Abs(reading.RightThumbstickY) * _SpeedLimit;
      }
    }
  }

  private void ArduinoDigitalWrite(byte port, PinState state)
  {
    // ignore duplicate commands
    var exists = _CurrentPinStates.ContainsKey(port);

    if (!exists
           || _CurrentPinStates[port] != state)
    {
      _CurrentPinStates[port] = state;
      _arduino.digitalWrite(port, state);
    }
  }
  
  private void ArduinoAnalogWrite(byte port, ushort value)
  {
    // ignore duplicate commands
    var exists = _CurrentSpeedValues.ContainsKey(port);

    if (!exists
          || _CurrentSpeedValues[port] != value)
    {
      _CurrentSpeedValues[port] = value;
      _arduino.analogWrite(port, value);
    }
  }
}

Credits

Pasfotosander300x450
Sander van de Velde

I started as a IT consultant in 1993. I like getting my hands dirty with software innovations and I try to implement these in my daily work

Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

From BT to WiFi: creating WiFi controlled Arduino Robot Car
Intermediate
  • 136
  • 3

Protip

NodeMCU ESP8266 in acsess point mode: the simpliest way to make Wi-Fi controlled Robot Car from Bluetooth Arduino Robot Car + Android App.

Sigfox Forest Fire Detector
Intermediate
  • 1,570
  • 9

Full instructions

How to prevent forest from burning? A small Sigfox signal can prevent natural disasters. We will use an Arduino MKRFOX + a flame detector

Human-Following Robot with Kinect
Intermediate
  • 2,242
  • 22

Full instructions

Instead of using single camera and complicated image recognition algorithms we can take advantage of Kinect libraries.

Using Common Cathode and Common Anode RGB LED with Arduino
Intermediate
  • 785
  • 14

Protip

Common Cathode and Common Anode RGB LEDs are two different kinds of RGB LEDs whose function is same but working is different.

Arduino Word Clock
Intermediate
  • 489
  • 8

Full instructions

A clock that let you read the time, for real!

Wall Mounted Textile MP3 Player
Intermediate
  • 66
  • 2

MP3 Player with fabric user interface using Arduino LilyPad.

Sign up / LoginProjectsPlatformsTopicsContestsLiveAppsBetaFree StoreBlog