Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Transmisor DIY Arduino RC

En el tutorial aprenderemos cómo construir un transmisor DIY Arduino RC. Muy a menudo necesito control inalámbrico para los proyectos que realizo, por lo que construí este controlador de radio multifuncional que se puede usar para casi todo.

Puede ver el siguiente video o leer el tutorial escrito a continuación.

Resumen

Ahora puedo controlar de forma inalámbrica cualquier proyecto Arduino con solo algunos pequeños ajustes en el lado del receptor. Este transmisor también se puede utilizar como cualquier transmisor RC comercial para controlar juguetes RC, automóviles, drones, etc. Para ese propósito, solo necesita un receptor Arduino simple que luego genera las señales apropiadas para controlar esos dispositivos RC comerciales.

Explicaré cómo funciona todo en este video a través de algunos ejemplos de cómo controlar un automóvil robot Arduino, controlar el Arduino Ant Robot de mi video anterior y controlar un motor de CC sin escobillas usando un ESC y algunos servomotores.

La comunicación por radio de este controlador se basa en el módulo transceptor NRF24L01 que, si se usa con una antena amplificada, puede tener un alcance estable de hasta 700 metros en espacios abiertos. Cuenta con 14 canales, 6 de los cuales son entradas analógicas y 8 entradas digitales.

Tiene dos joysticks, dos potenciómetros, dos interruptores de palanca, seis botones y, además, una unidad de medición interna que consiste en un acelerómetro y un giroscopio que también se puede usar para controlar cosas con solo mover o inclinar el controlador.

Diagrama del circuito del transmisor Arduino RC

Para empezar, echemos un vistazo al diagrama del circuito. El cerebro de este controlador RC es un Arduino Pro Mini que funciona con 2 baterías LiPo que producen alrededor de 7,4 voltios. Podemos conectarlos directamente al pin RAW del Pro Mini que tiene un regulador de voltaje que reduce el voltaje a 5V. Tenga en cuenta que hay dos versiones del Arduino Pro Mini, como la que tengo que funciona a 5 V y la otra funciona a 3,3 V.

Por otro lado, el módulo NRF24L01 necesita estrictamente 3,3 V y se recomienda que provenga de una fuente dedicada. Por lo tanto, necesitamos usar un regulador de voltaje de 3,3 V que esté conectado a las baterías y convertir los 7,4 V a 3,3 V. También necesitamos usar un condensador de desacoplamiento justo al lado del módulo para mantener el voltaje más estable, por lo que la comunicación por radio también será más estable. El módulo NRF24L01 se comunica con Arduino mediante el protocolo SPI, mientras que el módulo de acelerómetro y giroscopio MPU6050 utiliza el protocolo I2C.

Puede obtener los componentes necesarios para este tutorial de Arduino desde los siguientes enlaces:

  • Módulo transceptor NRF24L01……….. 
  • NRF24L01 + PA + LNA …………………….
  • Potenciómetro ……………………………….. 
  • Servomotor …………………………………… 
  • Interruptor de palanca ………………………….….. 
  • Joystick ………………………………………….. – este Joystick viene con una placa de conexión por lo que tendrá que desoldar el Joystick
  • Joystick sin tablero de conexiones ………… Ebay
  • Arduino Pro Mini……………………………….. – Necesita la versión PCB V2 o V3 para estas placas
  • Arduino Pro Mini como el que usé….. – PCB V1
  • Regulador de voltaje HT7333 3.3v ……………. De la tienda electrónica local:PCB V1 y PCB V2
  • Regulador de voltaje AMS1117 3.3v …………… Amazon / Banggood / AliExpress – placa de circuito impreso V3

Diseño de PCB

De hecho, terminé utilizando todos los pines analógicos y digitales del Arduino Pro Mini. Entonces, si trato de conectar todo usando cables de salto, será un gran desastre. Por lo tanto, diseñé una PCB personalizada utilizando el software gratuito de diseño de circuitos en línea EasyEDA.

Aquí tomé en consideración la ergonomía del controlador y lo diseñé para que pueda sostenerse fácilmente con dos manos, mientras que todos los controles están dentro del alcance de los dedos. Redondeé los bordes y agregué algunos agujeros de 3 mm para poder montar la PCB en algo más tarde. Coloqué los pines para programar el Arduino Pro Mini en la parte superior del controlador para que se pueda acceder fácilmente en caso de que queramos reprogramar el Arduino. También podemos notar aquí que usé los pines RX y TX del Arduino para los botones del joystick. Sin embargo, estas dos líneas deben desconectarse de cualquier cosa mientras cargamos el boceto en Arduino. Por lo tanto, se interrumpen con dos pines que luego se pueden conectar fácilmente usando tapas de puente simples.

Tenga en cuenta: Asegúrese de tener la versión correcta de Arduino Pro Mini para machear la PCB o modificar el diseño de la PCB de acuerdo con ella. Aquí hay una foto de comparación entre las tres versiones diferentes, dependiendo de tu Arduino y el regulador de voltaje.

Aquí hay un enlace a los archivos de proyecto de este diseño de PCB. Esto abre las tres versiones diferentes en pestañas separadas, para que pueda elegir la que necesita.

Entonces, una vez que terminé el diseño, generé el archivo Gerber necesario para fabricar la PCB.

Archivo Gerber:

Luego ordené el PCB de JLCPCB, que también es el patrocinador de este video.

Aquí podemos simplemente arrastrar y soltar el archivo Gerber y una vez cargado, podemos revisar nuestro PCB en el visor de Gerber. Si todo está bien, podemos continuar y seleccionar las propiedades que queremos para nuestra PCB. Esta vez elegí que el color de la PCB fuera negro. Y eso es todo, ahora podemos simplemente pedir nuestro PCB a un precio razonable. Tenga en cuenta que si es su primer pedido de JLCPCB, puede obtener hasta 10 PCB por solo $2.

Y aquí está. Realmente me encanta cómo resultó este PCB en este color negro. La calidad de la PCB es excelente y todo es exactamente igual que en el diseño.

Ensamblaje de la PCB

Bien, ahora podemos continuar con el ensamblaje de la PCB. Empecé soldando los pines del Arduino Pro Mini. Una manera fácil y buena de hacerlo es colocarlos en una placa de prueba para que permanezcan firmemente en su lugar mientras se sueldan.

El Pro Mini también tiene clavijas en los costados, pero tenga en cuenta que la ubicación de estas clavijas puede variar según el fabricante.

Para el modelo particular que tengo, necesito 5 pines para cada lado, dejando un pin GND vacío porque usé su área debajo de la PCB para ejecutar algunos rastros. Soldé el Arduino Pro Mini directamente en la PCB y corté la longitud de los encabezados. Justo al lado va el módulo de acelerómetro y giroscopio MPU6050.

Luego soldé el regulador de voltaje de 3.3V con un capacitor al lado y otro capacitor cerca del módulo NRF24L01. Este módulo tiene tres versiones diferentes y podemos usar cualquiera de ellas aquí.

Continué con los pines para programar el Arduino, los pines RX y TX, los pines de fuente de alimentación y el interruptor de encendido.

A continuación, para soldar los potenciómetros a la placa de circuito impreso, tuve que extender sus pines usando algunos cabezales de pines.

Podemos notar aquí que previamente corté la longitud de las perillas para poder colocar correctamente algunas tapas en ellas. Sin embargo, soldaremos los potenciómetros a la PCB un poco más tarde.

Luego inserté y soldé los dos interruptores de palanca y los dos joysticks en su lugar.

Finalmente lo que queda es soldar los cuatro pulsadores. Sin embargo, no tienen la altura adecuada, así que nuevamente usé encabezados de pines para extender un poco sus pines.

Y eso es todo, nuestro PCB ya está listo para que podamos continuar con la fabricación de la cubierta. Como me gusta cómo se ve la PCB y quiero que sea visible, decidí usar acrílico transparente para la cubierta.

Aquí tengo acrílico transparente de garrapatas de 4 mm que actualmente tiene una lámina protectora y parece ser azul. La idea para la tapa es hacer dos placas con la forma de la PCB y fijar una de ellas en la parte superior y la otra en la parte inferior de la PCB.

Así que marqué la forma de la placa de circuito impreso y, con una sierra manual para metal, corté el acrílico de acuerdo con ella.

Luego, usando una simple escofina, afiné la forma del acrílico. Las dos placas quedaron muy bien y combinan perfectamente con la PCB.

A continuación, marqué los lugares donde necesito hacer aberturas para que pasen los componentes. Usando un taladro de 3 mm, primero hice los 4 agujeros para asegurar las placas al PCB. Para estos agujeros también hice avellanados para que los pernos puedan colocarse al ras con las placas.

Para las aberturas de los interruptores de palanca y los potenciómetros usé un taladro de 6 mm, y para las aberturas del joystick usé una broca Forstner de 25 mm. Nuevamente, usando una escofina, puse a punto todas las aberturas.

Antes de ensamblar la cubierta, solo tenga en cuenta que en realidad soldé el cabezal del pin para la fuente de alimentación al revés para que pueda alcanzarse desde la parte posterior donde se ubicará la batería.

Bien, ahora podemos comenzar con el montaje de la cubierta. Comencé quitando la lámina protectora del acrílico, lo que debo admitir fue bastante satisfactorio porque el acrílico ahora estaba muy limpio. Así que primero aseguré los dos potenciómetros en la placa superior, inserté los pernos de montaje de 3 mm y coloqué los anillos de distancia de 11 mm en su lugar.

Luego fusioné y aseguré con cuidado la placa superior y la placa de circuito impreso con algunos pernos. En este punto finalmente soldé los potenciómetros a la PCB porque antes no sabía exactamente a qué altura se colocarían.

Luego, en la placa posterior, fijé el soporte de la batería con 2 pernos. Terminé el ensamblaje de la cubierta asegurando la placa posterior a la parte posterior de la PCB con los cuatro pernos de montaje.

Finalmente, podemos conectar las líneas de la batería a los pines de la fuente de alimentación, insertar y asegurar las perillas en los potenciómetros, insertar las perillas de los joysticks y conectar la antena al módulo NRF24l01. Y eso es todo, finalmente hemos terminado con el transmisor DIY Arduino RC.

Lo que queda ahora es programar el Arduino. Para programar una placa Pro Mini, necesitamos una interfaz USB a serie UART que se pueda conectar al encabezado de programación ubicado en la parte superior de nuestro controlador.

Luego, en el menú de herramientas de Arduino IDE, debemos seleccionar la placa Arduino Pro o Pro Mini, seleccionar la versión adecuada del procesador, seleccionar el puerto y seleccionar el método de programación para "USBasp".

Y ahora podemos cargar el código en Arduino.

Código de transmisor RC basado en Arduino DIY

Expliquemos cómo funciona el código del transmisor. Entonces, primero debemos incluir la biblioteca SPI y RF24 para la comunicación inalámbrica y la biblioteca I2C para el módulo del acelerómetro. Luego necesitamos definir las entradas digitales, algunas variables necesarias para el programa a continuación, definir el objeto de radio y la dirección de comunicación.

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;


RF24 radio(5, 6);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001"; // AddressCode language: Arduino (arduino)

Luego necesitamos definir una estructura donde almacenaremos los 14 valores de entrada del controlador. El tamaño máximo de esta estructura puede ser de 32 bytes porque ese es el límite del búfer NRF24L01 o la cantidad de datos que el módulo puede enviar a la vez.

/ Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structureCode language: Arduino (arduino)

En la sección de configuración, debemos inicializar el módulo MPU6050 y también podemos calcular el error de IMU, que es un valor que luego se usa al calcular los ángulos correctos del módulo.

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}Code language: Arduino (arduino)

Puede encontrar más detalles sobre cómo funcionan el acelerómetro y el giroscopio MEMS aquí. Próximamente habrá un tutorial dedicado para el MPU6050.

Luego, debemos inicializar la comunicación por radio, activar las resistencias pull-up internas de Arduino para todas las entradas digitales y establecer los valores predeterminados iniciales para todas las variables.

// Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  pinMode(jB1, INPUT_PULLUP);
  pinMode(jB2, INPUT_PULLUP);
  pinMode(t1, INPUT_PULLUP);
  pinMode(t2, INPUT_PULLUP);
  pinMode(b1, INPUT_PULLUP);
  pinMode(b2, INPUT_PULLUP);
  pinMode(b3, INPUT_PULLUP);
  pinMode(b4, INPUT_PULLUP);Code language: Arduino (arduino)

En la sección de bucle, comience leyendo todas las entradas analógicas, asigne sus valores de 0 a 1023 a valores de bytes de 0 a 255 porque ya definimos las variables en nuestra estructura como bytes. Cada entrada se almacena en la variable de datos particular de la estructura.

// Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 255
  data.j1PotY = map(analogRead(A0), 0, 1023, 0, 255);
  data.j2PotX = map(analogRead(A2), 0, 1023, 0, 255);
  data.j2PotY = map(analogRead(A3), 0, 1023, 0, 255);
  data.pot1 = map(analogRead(A7), 0, 1023, 0, 255);
  data.pot2 = map(analogRead(A6), 0, 1023, 0, 255);Code language: Arduino (arduino)

Solo debemos tener en cuenta que debido a que usamos las resistencias pull-up, las lecturas de los pines digitales son 0 cuando se presionan los botones.

// Read all digital inputs
  data.j1Button = digitalRead(jB1);
  data.j2Button = digitalRead(jB2);
  data.tSwitch2 = digitalRead(t2);
  data.button1 = digitalRead(b1);
  data.button2 = digitalRead(b2);
  data.button3 = digitalRead(b3);
  data.button4 = digitalRead(b4);Code language: Arduino (arduino)

Entonces, usando la función radio.write(), simplemente enviamos los valores de los 14 canales al receptor.

// Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));Code language: Arduino (arduino)

En caso de que el interruptor de palanca 1 esté encendido, entonces usamos los datos del acelerómetro y giroscopio en su lugar para el control.

if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }Code language: Arduino (arduino)

Entonces, en lugar de los valores X e Y del joystick 1, estamos usando los valores de ángulo que obtenemos de la IMU, que previamente convertimos de valores de -90 a +90 grados en valores de bytes de 0 a 255 de manera apropiada.

// Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);Code language: Arduino (arduino)

Así fue el código del transmisor, lo más importante fue definir la comunicación por radio y enviar los datos al receptor.

Aquí está el código Arduino completo para este transmisor DIY Arduino RC:

/*
        DIY Arduino based RC Transmitter
  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;


RF24 radio(5, 6);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001"; // Address

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  
  // Initialize interface to the MPU6050
  initialize_MPU6050();

  // Call this function if you need to get the IMU error values for your module
  //calculate_IMU_error();
  
  // Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  pinMode(jB1, INPUT_PULLUP);
  pinMode(jB2, INPUT_PULLUP);
  pinMode(t1, INPUT_PULLUP);
  pinMode(t2, INPUT_PULLUP);
  pinMode(b1, INPUT_PULLUP);
  pinMode(b2, INPUT_PULLUP);
  pinMode(b3, INPUT_PULLUP);
  pinMode(b4, INPUT_PULLUP);
  
  // Set initial default values
  data.j1PotX = 127; // Values from 0 to 255. When Joystick is in resting position, the value is in the middle, or 127. We actually map the pot value from 0 to 1023 to 0 to 255 because that's one BYTE value
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}
void loop() {
  // Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 255
  data.j1PotY = map(analogRead(A0), 0, 1023, 0, 255);
  data.j2PotX = map(analogRead(A2), 0, 1023, 0, 255);
  data.j2PotY = map(analogRead(A3), 0, 1023, 0, 255);
  data.pot1 = map(analogRead(A7), 0, 1023, 0, 255);
  data.pot2 = map(analogRead(A6), 0, 1023, 0, 255);
  // Read all digital inputs
  data.j1Button = digitalRead(jB1);
  data.j2Button = digitalRead(jB2);
  data.tSwitch2 = digitalRead(t2);
  data.button1 = digitalRead(b1);
  data.button2 = digitalRead(b2);
  data.button3 = digitalRead(b3);
  data.button4 = digitalRead(b4);
  // If toggle switch 1 is switched on
  if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }
  // Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));
}

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}

void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gury data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 4, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 32.8);
    GyroErrorY = GyroErrorY + (GyroY / 32.8);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
}

void read_IMU() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-8g, we need to divide the raw values by 4096, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 4096.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 4096.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0; // Z-axis value

  // Calculating angle values using
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) + 1.15; // AccErrorX ~(-1.15) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) - 0.52; // AccErrorX ~(0.5)

  // === Read gyro data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000;   // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 4, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 32.8; // For a 1000dps range we have to divide first the raw value by 32.8, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 32.8;
  GyroX = GyroX + 1.85; //// GyroErrorX ~(-1.85)
  GyroY = GyroY - 0.15; // GyroErrorY ~(0.15)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = GyroX * elapsedTime;
  gyroAngleY = GyroY * elapsedTime;

  // Complementary filter - combine acceleromter and gyro angle values
  angleX = 0.98 * (angleX + gyroAngleX) + 0.02 * accAngleX;
  angleY = 0.98 * (angleY + gyroAngleY) + 0.02 * accAngleY;
  // Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);
}Code language: Arduino (arduino)

Código del receptor

Ahora echemos un vistazo a cómo podemos recibir estos datos. Aquí hay un esquema simple del receptor Arduino y NRF24L01. Por supuesto, puedes usar cualquier otra placa Arduino.

Y aquí hay un código de receptor simple donde recibiremos los datos y simplemente los imprimiremos en el monitor serial para que sepamos que la comunicación funciona correctamente. Nuevamente, debemos incluir la biblioteca RF24 y definir los objetos y la estructura de la misma manera que en el código del transmisor. En la sección de configuración, cuando definimos la comunicación por radio, necesitamos usar la misma configuración que el transmisor y configurar el módulo como receptor usando la función radio.startListening().

/*
    DIY Arduino based RC Transmitter Project
              == Receiver Code ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening(); //  Set the module as receiver
  resetData();
}
void loop() {
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone has a throttle up and we lose connection, it can keep flying unless we reset the values
  }
  // Print the data in the Serial Monitor
  Serial.print("j1PotX: ");
  Serial.print(data.j1PotX);
  Serial.print("; j1PotY: ");
  Serial.print(data.j1PotY);
  Serial.print("; button1: ");
  Serial.print(data.button1);
  Serial.print("; j2PotX: ");
  Serial.println(data.j2PotX); 
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
  data.j1PotX = 127;
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}Code language: Arduino (arduino)

En el ciclo principal usando la función disponible () verificamos si hay datos entrantes. Si es verdadero, simplemente leemos los datos y los almacenamos en las variables de la estructura. Ahora podemos imprimir los datos en el monitor serie para comprobar si la transmisión funciona correctamente. También usando la función millis() y una declaración if, verificamos si seguimos recibiendo datos, o si no recibimos datos por un período de más de 1 segundo, luego restablecemos las variables a sus valores predeterminados. Usamos esto para evitar comportamientos no deseados, por ejemplo, si un dron acelera y perdemos la conexión, puede seguir volando a menos que restablezcamos los valores.

Eso es todo. Ahora podemos implementar este método de recepción de datos para cualquier proyecto de Arduino. Por ejemplo, aquí el código para controlar el coche robot Arduino de uno de mis videos anteriores.

Como actualización de este proyecto, hice un receptor RC dedicado basado en Arduino. Una vez más, se basa en la mini placa Arduino Pro y tiene varios servos y conexiones ESC listos para usar, colocados en una PCB compacta.

Arduino Robot Car Wireless Control usando RC Transmitter

Código Arduino:

Aquí necesitamos definir las bibliotecas, la estructura y la comunicación por radio como se explicó anteriormente. Luego, en el ciclo principal, solo necesitamos leer los datos entrantes y usar cualquiera de ellos para lo que queramos. En este caso utilizo los valores del joystick 1 para conducir el coche.

Arduino Ant Robot / Hexapod control usando Arduino RC Transmitter

Código Arduino:

Exactamente de la misma manera, hice que el Arduino Ant Robot de mi video anterior se controlara de forma inalámbrica con este transmisor Arduino RC. Solo necesitamos leer los datos y, de acuerdo con ellos, ejecutar las funciones apropiadas, como avanzar, izquierda, derecha, morder, atacar, etc.

ESC y servocontrol mediante transmisor RC

Por último, echemos un vistazo a cómo se puede usar este transmisor para controlar dispositivos RC comerciales.

Por lo general, para estos dispositivos necesitamos controlar sus servos o motores sin escobillas. Entonces, después de recibir los datos del transmisor, para controlar el servo, simplemente usamos la biblioteca Arduino Servo y usamos valores de 0 a 180 grados. Para controlar el motor sin escobillas usando ESC, podemos usar nuevamente la biblioteca de servos para generar la señal PWM de 50 Hz utilizada para controlar el ESC. Al variar el ciclo de trabajo de 1000 a 2000 microsegundos, controlamos las RPM del motor desde cero hasta el máximo. Sin embargo, más sobre el control de motores sin escobillas usando ESC en mi próximo tutorial.

Tenga en cuenta que en realidad no podemos vincular el sistema receptor RC estándar con este sistema NRF24L01 de 2,4 GHz. En su lugar, necesitamos modificar o crear nuestro propio receptor que consta de un módulo Arduino y NRF24L01. A partir de ahí, podemos generar las señales PWM o PPM apropiadas para controlar el dispositivo RC.

/*
    DIY Arduino based RC Transmitter Project
   == Receiver Code - ESC and Servo Control ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

Servo esc;  // create servo object to control the ESC
Servo servo1;
Servo servo2;
int escValue, servo1Value, servo2Value;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
struct Data_Package {
  byte j1PotX;
  byte j1PotY;
  byte j1Button;
  byte j2PotX;
  byte j2PotY;
  byte j2Button;
  byte pot1;
  byte pot2;
  byte tSwitch1;
  byte tSwitch2;
  byte button1;
  byte button2;
  byte button3;
  byte button4;
};

Data_Package data; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  radio.startListening(); //  Set the module as receiver
  resetData();
  esc.attach(9);
  servo1.attach(3);
  servo2.attach(4);
}
void loop() {
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone jas a throttle up, if we lose connection it can keep flying away if we dont reset the function
  }
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Controlling servos
  servo1Value = map(data.j2PotX, 0, 255, 0, 180);
  servo2Value = map(data.j2PotY, 0, 255, 0, 180);
  servo1.write(servo1Value);
  servo2.write(servo2Value);
  // Controlling brushless motor with ESC
  escValue = map(data.pot1, 0, 255, 1000, 2000); // Map the receiving value form 0 to 255 to 0 1000 to 2000, values used for controlling ESCs
  esc.writeMicroseconds(escValue); // Send the PWM control singal to the ESC
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
  data.j1PotX = 127;
  data.j1PotY = 127;
  data.j2PotX = 127;
  data.j2PotY = 127;
  data.j1Button = 1;
  data.j2Button = 1;
  data.pot1 = 1;
  data.pot2 = 1;
  data.tSwitch1 = 1;
  data.tSwitch2 = 1;
  data.button1 = 1;
  data.button2 = 1;
  data.button3 = 1;
  data.button4 = 1;
}Code language: Arduino (arduino)

So that’s it. I hope you enjoyed this video and learned something new. No dude en hacer cualquier pregunta en la sección de comentarios a continuación y consulte mi Colección de proyectos de Arduino.


Proceso de manufactura

  1. Kazoo
  2. Visualizador de música DIY LUMAZOID Arduino
  3. Haga una máquina de escribir para hacer tareas caseras en casa
  4. Voltímetro de bricolaje con Arduino y un teléfono inteligente
  5. Arduino + ESP Weather Box
  6. Patineta de realidad virtual DIY
  7. Máquina de tratamiento DIY Arduino RADIONICS
  8. Simulador de carreras de movimiento 2D DIY
  9. Idea de bricolaje con RFID
  10. DIY CNC VMC de 3 ejes
  11. DIY Arduino + Termómetro infrarrojo GY-906