Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Arduino Rover per Firmata & Xbox One Gamepad steuern

Komponenten und Materialien

Microsoft Xbox Controller + Wireless Adapter für Windows 1
SparkFun Bluetooth Modem BlueSMiRF Silver (oder HC-05/HC-06) 1
Arduino UNO 1

Apps und Online-Dienste

Über dieses Projekt

Vor einigen Monaten kaufte ich einen kleinen Rover (gesteuert von Arduino Uno) zum Schnäppchenpreis. Der Bausatz war sehr vollständig: Chassis, 2 Räder, 2 DC-Getriebemotoren, UNO R3, L298N Dual H-Bridge Motortreiber und weitere Komponenten. Auch Ultraschallsensor, Servo und Arduino Sensor Shield 5 waren dabei – ein echtes Schnäppchen.

Der Rover ist für autonomen Betrieb gedacht. Meine Idee: Xbox One Controller + Firmata-Protokoll für manuelle Steuerung. Und es funktioniert hervorragend!

Bausatz zusammenbauen

Der Aufbau ist nicht schwer. Zwar war die Anleitung auf Chinesisch, aber alles wirkt logisch. Nur eine Grundplatte – manche Komponenten oben, manche unten (jetzt Motortreiber).

Zwei verschiedene Batteriehalter wurden hinzugefügt. Beim Programmieren stellte sich heraus: Separate Stromversorgung nötig, damit die Motoren laufen.

Motoren anschließen – Pin-Belegung Motortreiber

Das Herz der Hardware ist diesmal nicht der Arduino, sondern der Motortreiber L298N. Er steuert Geschwindigkeit und Richtung beider Motoren per Signalen vom Arduino.

Pin-Belegung L298N:

Hinweis: Controller und Arduino haben getrennte Stromversorgungen. Für gemeinsamen Betrieb: Common Ground herstellen (siehe Punkt 4).

Motoren anschließen – Pin-Belegung Arduino

Arduino-Anschluss ist simpel: Ground und 5V der Stromversorgung an Arduino. Sechs Leitungen (ENA, IN1-4, ENB) an Pins D10 bis D5.

Pins 7&8 (bzw. 9&10 für anderen Motor) sind normale GPIOs für Motorrichtung. Beide LOW → Motor stoppt. Einer HIGH, anderer LOW → eine Richtung. Umgekehrt → andere Richtung.

Aber: Nur Pins setzen bewirkt nichts! Die Magie kommt von Pins 5 und 10 – PWM-fähig (gekennzeichnet mit ~). Werte 0–255 → Motor sehr langsam bis Höchstgeschwindigkeit.

Bluetooth anschließen

Bluetooth-Modul: RX/TX gekreuzt anschließen, 5V und Ground vom Arduino.

Firmata-Sketch auf Arduino

Der Standard-Firmata-Sketch „StandardFirmata“ reicht völlig! Aus Arduino IDE Beispiele laden, hochladen (evtl. TX/RX vorher abziehen).

Hinweis: Wegen schlechter Bluetooth-Qualität Baudrate im Sketch fest auf 9600 gesetzt.

Testen der Verbindung

Warum Firmata? Weil es einfach ist. Wie einfach? Sehr. Sogar ohne Programmierung: „Windows Remote Arduino Experience“ App (Store, auch Windows 10 Mobile).

  1. Mit bereits gepaartem HC-06 Bluetooth-Modul verbinden
  2. PWM-Seite: Digital Pin 5 aktivieren, Wert z. B. 128 setzen
  3. Achtung: Nächster Schritt lässt Motor laufen! Helm auf, Räder frei.
  4. Digital-Seite: Digital Pin 6 umschalten
  5. Wenn alles verbunden: Ein Motor dreht!
  6. Andere Geschwindigkeiten testen (höherer/niedrigerer PWM) oder Richtung ändern (Pin 6 LOW, Pin 7 HIGH)
  7. Gleiches für Pin 10 (PWM) und Pins 9, 8
  8. Beide Räder laufen → Jetzt coden…

Die UWP-App als Vermittler

Wir brauchen eine UWP-App zwischen Xbox One Controller und Rover. Ich bloggte bereits über Xbox One Controller – diesmal kombinieren wir das mit dem Rover.

Interface: Zwei Buttons, ein Textblock. Aufgaben: 1. Per Firmata über Bluetooth mit Arduino verbinden. 2. Nach Verbindung: Endlosschleife für Controller-Eingaben → Befehle umsetzen.

Gewünschte Steuerung: Klassische Panzersteuerung mit zwei Sticks. Nur die beiden Thumbsticks der Xbox One abfragen. Vorwärts/rückwärts → entsprechender Motor vorwärts/rückwärts.

Wichtig: Bluetooth-Fähigkeit in UWP-App hinzufügen. NuGet-Paket für Firmata installieren.

XAML-Snippet im MainForm-Grid für Buttons (siehe Code-Bereich). Code-Behind in zwei Teile: 1. Bluetooth+Firmata-Verbindung. 2. Xbox Controller abhören.

In der Schleife: Prüfen ob Thumbstick vorwärts/rückwärts/Stopp. Dann PWM-Wert bestimmen. Interessant: PWM-Schreiben in Firmata = Analogwert auf digitalem Port schreiben (keine eigene PWM-Methode in Arduino-Klasse).

Zwei Methoden ArduinoDigitalWrite und ArduinoAnalogWrite verhindern doppeltes Senden gleicher Werte – würde Kommunikation verstopfen und Arduino-Performance verschlechtern (bei Summer ohne Duplikat-Filter extrem schlechte Performance).

Bei niedrigen PWM-Pulsen „quitscht“ der Motor mit charakteristischem Ton – normales Verhalten. So fand ich raus: Zwei Stromquellen nötig. Beim ersten Mal dachte ich, Controller sei defekt. Nichts passierte. Bis ich einen Motor abzog → der andere quitschte.

Fazit

So funktioniert's: Thumbsticks steuern beide Motoren unabhängig per PWM + Richtung. Blinklicht nicht nur für Effekt – Sicherheit! Wenn Konstruktionen sich bewegen: Du bist schlau, das Ding nicht.

Code

XAML Steuerelemente für Kommunikationsstart

<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 der UWP App MainForm (C#)

public sealed partial class MainPage : Page {
  private BluetoothSerial _bluetooth;
  private RemoteDevice _arduino;
  private UwpFirmata _firmata = null;
  private Gamepad _Gamepad = null;
  private double _SpeedLimit = 0.75; // Max PWM 255 * 0.75
  private double _ActionPoint = 0.15; // Schwellenwert für Stopp
  private byte _LeftForward = 6, _LeftBackward = 7, _LeftValue = 5;
  private byte _RightForward = 9, _RightBackward = 8, _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;
  }
  // ... (Event-Handler für ConnectionLost, ConnectionFailed, ArduinoDeviceReady, OnConnectionEstablished, DisableEnableButtons, Gamepad_GamepadRemoved, Gamepad_GamepadAdded)

  private async void btnController_Click(object sender, RoutedEventArgs e) {
    DisableEnableButtons(false);
    while (true) {
      await Task.Delay(TimeSpan.FromMilliseconds(3));
      if (_Gamepad == null) continue;
      var reading = _Gamepad.GetCurrentReading();

      // Linker Stick → linker Motor
      if (Math.Abs(reading.LeftThumbstickY) < _ActionPoint) {
        ArduinoDigitalWrite(_LeftForward, PinState.LOW);
        ArduinoDigitalWrite(_LeftBackward, PinState.LOW);
      } else if (reading.LeftThumbstickY >= _ActionPoint) {
        ArduinoDigitalWrite(_LeftForward, PinState.HIGH);
        ArduinoDigitalWrite(_LeftBackward, PinState.LOW);
        ArduinoAnalogWrite(_LeftValue, (ushort)(255 * Math.Abs(reading.LeftThumbstickY) * _SpeedLimit));
      } else {
        ArduinoDigitalWrite(_LeftForward, PinState.LOW);
        ArduinoDigitalWrite(_LeftBackward, PinState.HIGH);
        ArduinoAnalogWrite(_LeftValue, (ushort)(255 * Math.Abs(reading.LeftThumbstickY) * _SpeedLimit));
      }

      // Rechter Stick → rechter Motor (analog)
      if (Math.Abs(reading.RightThumbstickY) < _ActionPoint) {
        ArduinoDigitalWrite(_RightForward, PinState.LOW);
        ArduinoDigitalWrite(_RightBackward, PinState.LOW);
      } else if (reading.RightThumbstickY >= _ActionPoint) {
        ArduinoDigitalWrite(_RightForward, PinState.HIGH);
        ArduinoDigitalWrite(_RightBackward, PinState.LOW);
        ArduinoAnalogWrite(_RightValue, (ushort)(255 * Math.Abs(reading.RightThumbstickY) * _SpeedLimit));
      } else {
        ArduinoDigitalWrite(_RightForward, PinState.LOW);
        ArduinoDigitalWrite(_RightBackward, PinState.HIGH);
        ArduinoAnalogWrite(_RightValue, (ushort)(255 * Math.Abs(reading.RightThumbstickY) * _SpeedLimit));
      }
    }
  }

  private void ArduinoDigitalWrite(byte port, PinState state) {
    var exists = _CurrentPinStates.ContainsKey(port);
    if (!exists || _CurrentPinStates[port] != state) {
      _CurrentPinStates[port] = state;
      _arduino.digitalWrite(port, state);
    }
  }

  private void ArduinoAnalogWrite(byte port, ushort value) {
    var exists = _CurrentSpeedValues.ContainsKey(port);
    if (!exists || _CurrentSpeedValues[port] != value) {
      _CurrentSpeedValues[port] = value;
      _arduino.analogWrite(port, value);
    }
  }
}

Herstellungsprozess

  1. RFID-Anwesenheitssystem mit Arduino & Python – Daten direkt in phpMyAdmin (XAMPP) speichern
  2. Universelle Android-Fernbedienung mit Arduino, 1Sheeld & IR-Steuerung
  3. Intelligentes Voltmeter mit Arduino & Smartphone bauen – Einfaches DIY-Projekt
  4. Fernsteuerung eines Roboterarms per IoT: Eigenbau mit Arduino MKR1000
  5. Frequenz & Tastverhältnis präzise messen mit Arduino UNO
  6. Echtzeit-Entfernungsmessung mit Arduino Sonar & Processing-Visualisierung
  7. Stufenlose LED-Helligkeitssteuerung mit Bolt IoT und Arduino UNO
  8. Intelligenter Arduino-Roboterarm bauen: Einfaches DIY-Tutorial
  9. TV per Alexa steuern mit Arduino IoT Cloud – Schritt-für-Schritt
  10. Kompaktes FM-Radio mit Arduino Nano und RDA5807M selbst bauen