Controla Arduino Rover usando Firmata y el controlador Xbox One
Componentes y suministros
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Aplicaciones y servicios en línea
|
Acerca de este proyecto
Hace unos meses compré un pequeño rover (controlado por un Arduino Uno) por muy buen precio. El kit era muy completo:chasis de automóvil, 2 ruedas de automóvil, 2 motores de engranajes de CC, un UNO R3, un controlador de motor de puente H dual L298N y varios otros componentes.
Este móvil está diseñado para ser programado para funcionamiento autónomo. Por lo tanto, también se agregan al kit un sensor ultrasónico y un servo. También hay un buen protector de sensor Arduino 5 en el kit. Sí, fue una verdadera ganga;-)
Pero mi idea era usar un controlador Xbox One y el protocolo Firmata para manejar este solo o uno de mis hijos. ¡Y funciona muy bien!
Aquí hay un video de la solución final:
Las partes principales utilizadas en este proyecto son:
- Un kit móvil (usamos para esta demostración solo un subconjunto de las partes:la placa base, las ruedas, los motores, el Arduino Uno, el soporte de la batería de 9 voltios y el controlador de motor de puente H dual L298N)
- Un soporte de batería adicional para 6 baterías AA
- Un módulo Bluetooth (HC-06)
- Un controlador Xbox One con adaptador inalámbrico para Windows (para conectarlo a una computadora portátil)
- Una computadora portátil (con Windows 10 + VS2015 + dongle Bluetooth)
- Una luz intermitente solo para un efecto dramático
Construyendo el kit
Construir el kit no es tan difícil. Aunque el manual de construcción estaba en chino, todo parece bastante lógico. Solo hay una placa base, así que tuve que poner algunos componentes encima y algunos en la parte inferior (ahora el controlador del motor):
En esta imagen se agregan dos portapilas diferentes. Durante la programación, descubrí que tenía que usar una fuente de alimentación separada solo para hacer funcionar los motores.
Conexión de los motores:disposición de los pines del controlador
El corazón del hardware esta vez, no es el Arduino Uno sino el controlador del motor.
“El L298 es un controlador de puente en H doble para motores DC con escobillas y motores paso a paso. Admite un amplio rango de voltaje operativo y puede entregar 2 A por canal en un paquete de orificios pasantes que es accesible para proyectos de bricolaje ".
Este controlador controlará la velocidad y dirección de cada uno de los dos motores, usando señales provenientes del Arduino.
La disposición de los pines del controlador de motor de puente H dual L298N es:
- Más + del motor de CC 1
- Menos - del motor de CC 1
- ENTRADA. Suministro 9 voltios desde un soporte de batería separado
- Terreno común. Conectado a mi soporte de batería separado y al Arduino
- Apagar . Puede producir 5 voltios ( no utilizado . Mi Arduino recibe energía de otro soporte de batería)
- ENA conectado a Arduino D10. Este puerto es capaz de PWM (blanco)
- IN1 conectado a Arduino D9. (gris)
- IN2 conectado a Arduino D8. (violeta)
- IN3 conectado a Arduino D7. (azul)
- IN4 conectado a Arduino D6. (verde)
- ENB conectado a Arduino D5. Este puerto es capaz de PWM (amarillo)
- Más + del motor de CC 2
- Menos - del motor de CC 2
- El jersey junto a 2 y 3 NO se ha eliminado porque no excedo la potencia de entrada por encima de 12 voltios (hasta 35 voltios) (puente no marcado en la imagen)
Nota:el controlador tiene su propia fuente de alimentación. El Arduino también tiene uno. Para que las cosas sigan funcionando (sin explotar, bríndeles un punto en común ) . Consulte el punto 4 anterior)
Conexión de los motores:disposición de los pines de Arduino
Conectar el Arduino es bastante sencillo. Conectamos la tierra y los 5 voltios de la fuente de alimentación al Arduino. Y conectamos las seis líneas (ENA, IN1-4 y ENB) al pin D10 hasta D5.
Debe quedar claro que los puertos 7 y 8 (y 9 y 10 para el otro motor) son solo puertos GPIO normales. Estos se utilizarán para la dirección del motor. Si ambos puertos (por ejemplo, 7 y 8) están BAJOS, el motor no hará nada (se detiene). Si uno es ALTO y el otro BAJO, el motor funcionará en una dirección. Si se conecta al revés (el primero está configurado en BAJO y el otro en ALTO), el motor conectado funcionará en la otra dirección.
Pero ... solo colocar estos pines no dará como resultado nada. ¡Sin partes móviles todavía!
La magia vendrá de los pines 5 y 10. Estos son pines "especiales" que pueden generar una señal PWM. Establecer un valor entre 0 y 255 hará que el motor funcione MUY lento (parado) o a alta velocidad.
Nota:Cada puerto del Arduino Uno capaz de PWM está marcado con una tilde (la ~).
Conexión de Bluetooth
El módulo Bluetooth que uso solo necesita estar conectado al puerto RX y TX (cruce las líneas) y necesita 5 voltios de potencia y tierra del Arduino.
Bosquejo de Firmata en Arduino
¡El boceto de Firmata "StandardFirmata" es todo lo que necesitamos en Arduino! Solo obténgalo de los ejemplos de Arduino IDE y cárguelo (tal vez necesite desanclar el TX / RX primero para completar la carga).
Nota:debido a la falta de calidad de mi módulo Bluetooth, siempre bajo la velocidad en baudios que está codificada dentro del boceto y la configuro en 9600.
Caballeros, enciendan sus motores
O prueba la conexión ...
Entonces, ¿por qué estoy usando Firmata? porque es fácil. ¿Cuan sencillo? Muy fácil. E incluso se puede hacer sin programación. Simplemente inicie la aplicación Windows Remote Arduino Experience (disponible en la tienda y también funciona en un dispositivo Windows 10 Mobile).
Primero deberá conectarse al módulo Bluetooth HC-6 ya emparejado.
Cuando esté emparejado, vaya a la página PWM. Habilite el pin digital 5 y asígnele un valor de, digamos, 128.
Cuidado:el siguiente paso hará que su motor funcione. Casco puesto y ruedas de la harina. Sabrá por qué cuando lo vea.
Luego vaya a la página Digital. Y accione el interruptor del pin digital 6.
Ahora, si todo está conectado y funcionando, ¡uno de los motores girará!
Si es así, puede verificar otras velocidades (usando un valor PWM más alto o más bajo) o cambiar la dirección (establezca el pin digital 6 en 0 voltios y el pin digital 7 en 5 voltios).
Y ahí lo tienes. ¡Puedes controlar esa rueda!
Pero hay más, lo mismo ocurre con el pin 10 (PWM) y el pin digital 9 y el pin digital 8.
Ambas ruedas en marcha. Ahora empieza a codificar ...
La aplicación para UWP como creador de coincidencias
Debe quedar claro que necesitamos una nueva aplicación para UWP entre el controlador de Xbox One y el móvil.
Ya escribí en un blog sobre el uso del controlador de Xbox One aquí. Esta vez combinaremos ese conocimiento con nuestro vehículo.
Veamos la interfaz de nuestra aplicación para UWP:
Es bastante aburrido, dos botones y un bloque de texto. No tendré nada más que hacer luego de conectarme primero al Arduino usando Firmata. Y una vez realizada la conexión, el botón del controlador tendrá que iniciar un bucle gigante para leer la entrada del controlador y convertirla en comandos útiles.
Y lo que queremos crear es este clásico control de tanque con dos manijas. Todo lo que necesitamos es verificar las dos palancas de control en el controlador de Xbox One. Moverlos hacia adelante y hacia atrás también iniciará el motor correspondiente hacia adelante y hacia atrás:
Nota:si inicia una nueva aplicación para UWP, no olvide agregar la función Bluetooth. Y tendrá que instalar el paquete nuget para Firmata.
Primero agregamos el fragmento de código XAML (consulte la sección de código para el código fuente Xaml) en la cuadrícula del formulario principal para que tengamos algunos botones.
A continuación, agregamos el código detrás (consulte la sección de código para el código fuente de C #) del formulario principal. Básicamente, estoy dividido en dos partes. Primero hacemos una conexión por Bluetooth con el protocolo Firmata. A continuación, comenzamos a escuchar la entrada en el controlador de Xbox One.
Dentro del ciclo para verificar los controles, decidimos si un joystick apunta hacia adelante o hacia atrás o si está en el rango de "parada". Después de eso, decidimos cuál será el valor del pin PWM.
Es interesante ver que escribir un valor PWM se representa en Firmata como escribir un valor analógico en un puerto digital. No hay un método PWM especial en la clase Arduino.
He agregado dos métodos “ArduinoDigitalWrite” y “ArduinoAnalogWrite” para evitar escribir el mismo valor una y otra vez en Arduino. Esto saturará la comunicación y degradará el rendimiento del Arduino. (En un diseño mucho más rico agregué un timbre. Sin ignorar los comandos duplicados, el rendimiento del timbre fue extremadamente pobre y terrible de escuchar).
Cuando los motores obtienen los pulsos de PMW bajos, el motor no está comenzando a funcionar directamente, emitirá un sonido muy distintivo. Este es un comportamiento normal. Y así fue como descubrí que tenía que agregar dos fuentes de energía. La primera vez que conecté todo, pensé que el controlador estaba roto. No pasó nada. Hasta que desconecté uno de los motores y el otro empezó a gemir.
Así es como funciona:
Nota al pie:la luz intermitente no es solo para un efecto dramático. Siempre que sus creaciones comiencen a moverse, tenga en cuenta la seguridad. El artilugio es tonto, ¡no lo eres! Por lo tanto, puse esta luz encima en primer lugar.
Código
- Controles Xaml para iniciar la comunicación
- Código subyacente del formulario principal de la aplicación para UWP
Controles Xaml para iniciar la comunicación snippets
Pegue esto en el formulario principal de su nueva aplicación para UWPCódigo subyacente del formulario principal de la aplicación para UWP C #
Este código se conecta al móvil usando Firmata y pasa los comandos del controlador Xbox Oneclase parcial sellada pública MainPage:Page {private BluetoothSerial _bluetooth; Private RemoteDevice _arduino; privado UwpFirmata _firmata =null; Gamepad privado _Gamepad =null; // Nunca proporcionamos un PWM de más de 255 * 0,75 private double _SpeedLimit =0.75; // los valores por debajo de este valor absoluto detienen el rover private double _ActionPoint =0.15; byte privado _LeftForward =6; byte privado _LeftBackward =7; byte privado _LeftValue =5; byte privado _RightForward =9; byte privado _RightBackward =8; byte privado _RightValue =10; Diccionario privado_CurrentPinStates =new Dictionary (); Diccionario privado _CurrentSpeedValues =new Dictionary (); Public MainPage () {this.InitializeComponent (); } private void btnStart_Click (remitente del objeto, RoutedEventArgs e) {btnStart.IsEnabled =false; Gamepad.GamepadAdded + =Gamepad_GamepadAdded; Gamepad.GamepadRemoved + =Gamepad_GamepadRemoved; _bluetooth =nuevo 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 (mensaje de cadena) {await Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => {tbRead.Text ="ConnectionLost" + mensaje; btnStart.IsEnabled =true;}); } private async void BluetoothConnectionFailed (mensaje de cadena) {await Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => {tbRead.Text ="ConnectionFailed" + mensaje; btnStart.IsEnabled =true;}); } private async void ArduinoDeviceReady () {await Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => {tbRead.Text ="Dispositivo listo";}); } private void OnConnectionEstablished () {var action =Dispatcher.RunAsync (CoreDispatcherPriority.Normal, new DispatchedHandler (() => {DisableEnableButtons (true); ArduinoDigitalWrite (_LeftForward, PinState.LOW); ArduinoDigitalBackWrite (_ (_RightBackward, PinState.LOW); ArduinoDigitalWrite (_RightForward, PinState.LOW);})); } private void DisableEnableButtons (bool enabled) {// Desactiva todos los botones. De lo contrario // la 'A' presionará el enfocado. btnController.IsEnabled =habilitado; btnStart.IsEnabled =habilitado; } Private async void Gamepad_GamepadRemoved (remitente del objeto, Gamepad e) {_Gamepad =null; aguardar Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => {tbRead.Text ="Controlador eliminado";}); } Private async void Gamepad_GamepadAdded (remitente del objeto, Gamepad e) {_Gamepad =e; aguardar Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => {tbRead.Text ="Controlador agregado";}); } private async void btnController_Click (remitente del objeto, RoutedEventArgs e) {DisableEnableButtons (false); while (verdadero) {espera Task.Delay (TimeSpan.FromMilliseconds (3)); if (_Gamepad ==null) {continuar; } // Obtiene el estado actual 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 (puerto de bytes, estado PinState) {// ignora los comandos duplicados var existe =_CurrentPinStates.ContainsKey (puerto); if (! existe || _CurrentPinStates [puerto]! =estado) {_CurrentPinStates [puerto] =estado; _arduino.digitalWrite (puerto, estado); }} private void ArduinoAnalogWrite (puerto de bytes, valor corto) {// ignora los comandos duplicados var existe =_CurrentSpeedValues.ContainsKey (puerto); if (! existe || _CurrentSpeedValues [puerto]! =valor) {_CurrentSpeedValues [puerto] =valor; _arduino.analogWrite (puerto, valor); }}}
Proceso de manufactura
- Sistema de asistencia que usa Arduino y RFID con Python
- Control remoto universal usando Arduino, 1Sheeld y Android
- Voltímetro de bricolaje con Arduino y un teléfono inteligente
- Uso de IoT para controlar de forma remota un brazo robótico
- Medición de frecuencia y ciclo de trabajo con Arduino
- Sonda usando arduino y visualización en procesamiento IDE
- Control del brillo del LED usando Bolt y Arduino
- Brazo robótico simple e inteligente con Arduino
- Control total de su televisor con Alexa y Arduino IoT Cloud
- Radio FM usando Arduino y RDA8057M
- Controla tu sistema de iluminación mediante un teléfono inteligente