Contrôlez un rover Arduino avec Firmata et une manette Xbox One
Composants et fournitures
| Composant | Détails |
|---|---|
| Manette Xbox One + adaptateur sans fil Windows | Connexion PC via adaptateur officiel |
| Module Bluetooth (BlueSMiRF Silver, HC-05 ou HC-06) | Liaison PC ↔ Arduino |
| Arduino UNO | Contrôleur rover |
| Kit rover (châssis, 2 roues, 2 moteurs DC, L298N, shield capteurs) | Exemple kit complet bon marché |
| 2 porte-piles séparés | 9V pour Arduino + 6×AA (9V) pour moteurs |
| Feu clignotant (sécurité) | Optionnel mais recommandé |
Logiciel
- Windows 10 IoT Core (application UWP intermédiaire)
- Visual Studio 2015+
- Package NuGet Firmata
À propos du projet
Un kit rover bon marché (châssis, moteurs, Uno, L298N, shield) destiné à l'autonome (ultrason, servo). Mon but : le piloter à la manette Xbox One via Firmata. Résultat : ça marche parfaitement !
Montage mécanique
Manuel en chinois mais logique. Deux porte-piles nécessaires : un pour l'Arduino, un pour les moteurs (le L298N ne peut pas tout alimenter).
Câblage moteur - L298N
Le L298N pilote 2 moteurs DC (2A/canal). Connexions :
| L298N | Arduino / Alimentation |
|---|---|
| ENA (PWM moteur 1) | D10 (PWM ~) |
| IN1 (sens 1) | D9 |
| IN2 (sens 2) | D8 |
| IN3 (sens 1) | D7 |
| IN4 (sens 2) | D6 |
| ENB (PWM moteur 2) | D5 (PWM ~) |
| Alim moteurs (+9V) | Porte-piles 6×AA |
| Masse commune | Arduino GND + pile moteurs |
| Jumper 12V | LAISSÉ (alim < 12V) |
Logique direction : IN1/IN2 (ou IN3/IN4) : LOW/LOW = stop, HIGH/LOW = sens 1, LOW/HIGH = sens inverse. PWM sur ENA/ENB (0-255) = vitesse.
Câblage Arduino
6 fils (D5-D10) + masse commune + 5V si nécessaire.
Bluetooth
Module HC-06 : RX↔TX (croisé), 5V, GND depuis Arduino.
Firmata sur Arduino
Utiliser l'exemple StandardFirmata (IDE Arduino → Fichier → Exemples → Firmata). Téléverser (débrancher RX/TX avant). Astuce : baisser le baudrate codé en dur à 9600 si module Bluetooth capricieux.
Test rapide sans code : Windows Remote Arduino Experience
- App Store Windows → « Windows Remote Arduino Experience »
- Connexion Bluetooth HC-06
- Page PWM → Activer D5, valeur 128
- Page Digital → Basculer D6 → Un moteur tourne !
- Tester D7 (sens inverse), D10/D8/D9 (second moteur)
Application UWP : le pont manette ↔ Firmata
Interface minimale : 2 boutons (Connexion, Manette) + zone texte. Logique :
- Connexion Bluetooth + Firmata
- Boucle lecture manette Xbox (sticks gauche/droite)
- Contrôle « char d'assaut » : stick Y = avant/arrière moteur correspondant
- Seuil mort (
_ActionPoint = 0.15) = stop - Limite vitesse (
_SpeedLimit = 0.75) = 75% max - Écriture PWM =
analogWritevia Firmata - Optimisation : n'envoyer commande que si valeur change (dictionnaires
_CurrentPinStates,_CurrentSpeedValues)
Note : Au démarrage PWM faible, le moteur « chante » (normal). C'est ainsi qu'on a découvert le besoin de 2 alimentations séparées.
Code : XAML (interface)
<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 : C# (code-behind UWP)
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;
private double _actionPoint = 0.15;
private byte _leftFwd = 6, _leftBwd = 7, _leftPwm = 5;
private byte _rightFwd = 9, _rightBwd = 8, _rightPwm = 10;
private Dictionary<byte, PinState> _pinStates = new Dictionary<byte, PinState>();
private Dictionary<byte, ushort> _speedValues = new Dictionary<byte, ushort>();
public MainPage() { InitializeComponent(); }
private void btnStart_Click(...) {
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 OnConnectionEstablished() {
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
btnController.IsEnabled = true;
ArduinoDigitalWrite(_leftFwd, PinState.LOW);
ArduinoDigitalWrite(_leftBwd, PinState.LOW);
ArduinoDigitalWrite(_rightFwd, PinState.LOW);
ArduinoDigitalWrite(_rightBwd, PinState.LOW);
});
}
private async void btnController_Click(...) {
btnController.IsEnabled = false; btnStart.IsEnabled = false;
while (true) {
await Task.Delay(3);
if (_gamepad == null) continue;
var reading = _gamepad.GetCurrentReading();
// Moteur gauche (stick gauche Y)
if (Math.Abs(reading.LeftThumbstickY) < _actionPoint) {
ArduinoDigitalWrite(_leftFwd, PinState.LOW);
ArduinoDigitalWrite(_leftBwd, PinState.LOW);
} else if (reading.LeftThumbstickY >= _actionPoint) {
ArduinoDigitalWrite(_leftFwd, PinState.HIGH);
ArduinoDigitalWrite(_leftBwd, PinState.LOW);
ArduinoAnalogWrite(_leftPwm, (ushort)(255 * Math.Abs(reading.LeftThumbstickY) * _speedLimit));
} else {
ArduinoDigitalWrite(_leftFwd, PinState.LOW);
ArduinoDigitalWrite(_leftBwd, PinState.HIGH);
ArduinoAnalogWrite(_leftPwm, (ushort)(255 * Math.Abs(reading.LeftThumbstickY) * _speedLimit));
}
// Moteur droit (stick droit Y) - logique identique
if (Math.Abs(reading.RightThumbstickY) < _actionPoint) { ... }
else if (reading.RightThumbstickY >= _actionPoint) { ... }
else { ... }
}
}
private void ArduinoDigitalWrite(byte port, PinState state) {
if (!_pinStates.ContainsKey(port) || _pinStates[port] != state) {
_pinStates[port] = state;
_arduino.digitalWrite(port, state);
}
}
private void ArduinoAnalogWrite(byte port, ushort value) {
if (!_speedValues.ContainsKey(port) || _speedValues[port] != value) {
_speedValues[port] = value;
_arduino.analogWrite(port, value);
}
}
// ... gestion événements Gamepad/Bluetooth (voir source complet)
}
Sécurité
Le feu clignotant n'est pas que décoratif : quand votre création se déplace, vous êtes responsable. La machine est bête, pas vous !
Processus de fabrication
- Système de pointage RFID fiable avec Arduino et Python (base de données phpMyAdmin)
- Construire une télécommande Android universelle avec Arduino, 1Sheeld et contrôle IR
- Construire un Voltmètre Intelligent avec Arduino et Smartphone – Projet DIY Facile
- Contrôle IoT à Distance d'un Bras Robotique Personnalisé avec Arduino MKR1000
- Mesure Précise de Fréquence et Rapport Cyclique avec Arduino UNO
- Mesure de distance en temps réel par sonar Arduino et visualisation Processing
- Contrôle fluide de la luminosité LED avec Bolt IoT et Arduino UNO
- Construisez un Bras Robotique Intelligent Contrôlé par Arduino : Tutoriel DIY Facile
- Contrôler votre TV avec Alexa via Arduino IoT Cloud – Guide étape par étape