Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Transmissor RC Arduino DIY


No tutorial vamos aprender como construir um transmissor DIY Arduino RC. Muitas vezes preciso de controle sem fio para os projetos que faço, por isso construí este controlador de rádio multifuncional que pode ser usado para praticamente tudo.

Você pode assistir ao vídeo a seguir ou ler o tutorial escrito abaixo.

Visão geral


Agora posso controlar sem fio qualquer projeto Arduino com apenas alguns pequenos ajustes no lado do receptor. Este transmissor também pode ser usado como qualquer transmissor RC comercial para controlar brinquedos RC, carros, drones e assim por diante. Para isso, basta um simples receptor Arduino que gera os sinais apropriados para controlar esses dispositivos RC comerciais.

Vou explicar como tudo funciona neste vídeo através de alguns exemplos de controle de um carro robô Arduino, controlando o Arduino Ant Robot do meu vídeo anterior e controlando um motor DC sem escova usando um ESC e alguns servomotores.

A comunicação de rádio deste controlador é baseada no módulo transceptor NRF24L01 que se usado com uma antena amplificada pode ter um alcance estável de até 700 metros em espaço aberto. Possui 14 canais, sendo 6 entradas analógicas e 8 entradas digitais.

Possui dois joysticks, dois potenciômetros, dois interruptores, seis botões e, adicionalmente, uma unidade de medição interna composta por um acelerômetro e um giroscópio que também pode ser usado para controlar coisas apenas movendo ou inclinando o controlador.

Diagrama de circuito do transmissor RC do Arduino


Para começar, vamos dar uma olhada no diagrama de circuito. O cérebro deste controlador RC é um Arduino Pro Mini que é alimentado por 2 baterias LiPo produzindo cerca de 7,4 volts. Podemos conectá-los diretamente ao pino RAW do Pro Mini que possui um regulador de tensão que reduziu a tensão para 5V. Observe que existem duas versões do Arduino Pro Mini, como a que tenho que opera em 5V e a outra opera em 3,3V.

Por outro lado, o módulo NRF24L01 precisa estritamente de 3,3V e é recomendável vir de uma fonte dedicada. Portanto, precisamos usar um regulador de tensão de 3,3V que é conectado às baterias e converter os 7,4V em 3,3V. Também precisamos usar um capacitor de desacoplamento ao lado do módulo para manter a tensão mais estável, assim a comunicação de rádio também será mais estável. O módulo NRF24L01 se comunica com o Arduino utilizando o protocolo SPI, enquanto o módulo acelerômetro e giroscópio MPU6050 utiliza o protocolo I2C.

Você pode obter os componentes necessários para este tutorial do Arduino nos links abaixo:
  • Módulo Transceptor NRF24L01……….. 
  • NRF24L01 + PA + LNA …………………….
  • Potenciômetro ………………………………….. 
  • Servomotor …………………………………… 
  • Alternar interruptor ……………………………….….. 
  • Joystick ………………………………………….. – este joystick vem com uma placa de fuga, então você terá que dessoldar o joystick dele
  • Joystick sem breakout board ………… Ebay
  • Arduino Pro Mini…………………………….. – Você precisa da versão PCB V2 ou V3 para estas placas
  • Arduino Pro Mini como o que eu usei….. – PCB V1
  • HT7333 3.3v regulador de tensão ……………. Da loja de eletrônicos local – PCB V1 e PCB V2
  • Regulador de tensão AMS1117 3,3v …………… Amazon / Banggoood / AliExpress – PCB V3

Projeto de PCB


Na verdade, acabei utilizando todos os pinos analógicos e digitais do Arduino Pro Mini. Então, agora, se eu tentar conectar tudo usando fios de salto, será uma bagunça. Portanto, projetei um PCB personalizado usando o software de design de circuito online gratuito EasyEDA.

Aqui eu levei em consideração a ergonomia do controlador e o projetei para ser facilmente segurado por duas mãos, enquanto todos os controles estão dentro do alcance dos dedos. Fiz as bordas arredondadas e adicionei alguns furos de 3 mm para que eu possa montar a PCB em algo mais tarde. Coloquei os pinos para programar o Arduino Pro Mini na parte superior do controlador para que possam ser acessados ​​facilmente caso queiramos reprogramar o Arduino. Também podemos notar aqui que usei os pinos RX e TX do Arduino para os botões do joystick. No entanto, essas duas linhas precisam ser desconectadas de qualquer coisa enquanto estamos enviando o esboço para o Arduino. Portanto, eles são interrompidos com dois pinos que podem ser facilmente conectados usando tampas de jumper simples.

Observação: Certifique-se de ter a versão correta do Arduino Pro Mini para usinar o PCB ou modificar o design do PCB de acordo com ele. Aqui está uma foto de comparação entre as três versões diferentes, dependendo do seu Arduino e do regulador de tensão.

Aqui está um link para os arquivos de projeto deste design de PCB. Isso abre as três versões diferentes em guias separadas, para que você possa escolher a que precisa.

Assim que terminei o projeto, gerei o arquivo Gerber necessário para a fabricação do PCB.

arquivo Gerber:

Então encomendei o PCB da JLCPCB que também é o patrocinador deste vídeo.

Aqui podemos simplesmente arrastar e soltar o arquivo Gerber e, uma vez carregado, podemos revisar nosso PCB no visualizador Gerber. Se tudo estiver bem, podemos continuar e selecionar as propriedades que queremos para o nosso PCB. Desta vez eu escolhi a cor do PCB para ser preto. E é isso, agora podemos simplesmente encomendar nosso PCB a um preço razoável. Observe que, se for seu primeiro pedido da JLCPCB, você poderá obter até 10 PCBs por apenas US $ 2.

E aqui está. Eu realmente amo como este PCB ficou nesta cor preta. A qualidade do PCB é ótima, e tudo é exatamente igual ao design.

Montagem do PCB


Ok, agora podemos seguir em frente com a montagem do PCB. Comecei soldando os pinos do Arduino Pro Mini. Uma maneira fácil e boa de fazer isso é colocá-los em uma placa de ensaio e assim eles permanecerão firmes no lugar durante a soldagem.

O Pro Mini também possui pinos nas laterais, mas observe que a localização desses pinos pode variar dependendo do fabricante.

Para o modelo específico que tenho, preciso de 5 pinos para cada lado, deixando um pino GND vazio porque usei sua área abaixo na PCB para executar alguns rastreamentos. Soldei o Arduino Pro Mini diretamente no PCB e cortei o comprimento dos execs dos headers. Logo ao lado está o módulo de acelerômetro e giroscópio MPU6050.

Então soldei o regulador de tensão de 3,3V com um capacitor próximo a ele e outro capacitor próximo ao módulo NRF24L01. Este módulo tem três versões diferentes e podemos usar qualquer uma delas aqui.

Continuei com os pinos para programação do Arduino, os pinos RX e TX, os pinos da fonte de alimentação e a chave liga/desliga.

Em seguida, para soldar os potenciômetros ao PCB, tive que estender seus pinos usando alguns cabeçalhos de pinos.

Podemos notar aqui que eu cortei anteriormente o comprimento dos botões para que eu possa encaixar corretamente algumas tampas neles. No entanto, vamos soldar os potenciômetros ao PCB um pouco mais tarde.

Em seguida, inseri e soldei os dois interruptores e os dois joysticks no lugar.

Finalmente o que resta é soldar os quatro botões. No entanto, eles não têm a altura adequada, então, novamente, usei cabeçalhos de pinos para estender um pouco os pinos.

E é isso, nosso PCB já está pronto para que possamos continuar fazendo a capa para ele. Como gosto da aparência do PCB e quero ficar visível, decidi usar acrílico transparente para a tampa.

Aqui eu tenho acrílico transparente carrapato de 4 mm que atualmente tem uma película protetora e parece ser azul. A ideia da tampa é fazer duas placas com o formato da PCB e prender uma delas na parte de cima e a outra na parte de baixo da PCB.

Então marquei o formato do PCB e usando uma serra manual de metal cortei o acrílico de acordo com ele.

Então, usando uma grosa simples, ajustei a forma do acrílico. As duas placas ficaram ótimas e combinam perfeitamente com o PCB.

Em seguida marquei os locais onde preciso fazer aberturas para a passagem dos componentes. Usando uma furadeira de 3mm, primeiro fiz os 4 furos para prender as placas ao PCB. Para esses furos também fiz contra pias para que os parafusos possam ser colocados em flash com as placas.

Para as aberturas dos interruptores e dos potenciômetros usei furadeira de 6mm, e para as aberturas do joystick usei broca Forstner de 25mm. Novamente, usando uma grosa, eu ajustei todas as aberturas.

Antes de montar a tampa, apenas uma observação que eu realmente soldei o pino da fonte de alimentação de cabeça para baixo para que possa ser alcançado pela parte de trás onde a bateria estará localizada.

Ok, agora podemos começar com a montagem da tampa. Comecei descascando a película protetora do acrílico, o que devo admitir que foi bastante satisfatório porque o acrílico estava tão limpo agora. Então, primeiro eu prendi os dois potenciômetros na placa superior, inseri os parafusos de montagem de 3 mm e coloquei os anéis de distância de 11 mm no lugar.

Então eu cuidadosamente mesclei e prendi a placa superior e o PCB usando alguns parafusos. Neste ponto eu finalmente soldei os potenciômetros ao PCB porque antes eu não sabia exatamente em que altura eles seriam colocados.

Em seguida, na placa traseira, prendi o suporte da bateria usando 2 parafusos. Terminei a montagem da tampa prendendo a placa traseira na parte de trás da PCB usando os quatro parafusos de montagem.

Por fim, podemos conectar as linhas da bateria aos pinos da fonte de alimentação, inserir e prender os botões nos potenciômetros, inserir os botões dos joysticks e conectar a antena ao módulo NRF24l01. E é isso, finalmente terminamos com o transmissor DIY Arduino RC.

O que resta agora é programar o Arduino. Para programar uma placa Pro Mini, precisamos de uma interface USB para UART serial que pode ser conectada ao cabeçalho de programação localizado na parte superior do nosso controlador.

Em seguida, no menu de ferramentas do Arduino IDE, precisamos selecionar a placa Arduino Pro ou Pro Mini, selecionar a versão adequada do processador, selecionar a porta e selecionar o método de programação para “USBasp”.

E agora podemos fazer o upload do código para o Arduino.

Código de transmissor RC baseado em Arduino DIY


Vamos explicar como funciona o código do transmissor. Então, primeiro precisamos incluir a biblioteca SPI e RF24 para a comunicação sem fio e a biblioteca I2C para o módulo acelerômetro. Então precisamos definir as entradas digitais, algumas variáveis ​​necessárias para o programa abaixo, definir o objeto rádio e o endereço de comunicação.
#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)

Em seguida, precisamos definir uma estrutura onde armazenaremos os 14 valores de entrada do controlador. O tamanho máximo dessa estrutura pode ser de 32 bytes porque esse é o limite de buffer NRF24L01 ou a quantidade de dados que o módulo pode enviar de uma só 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)

Na seção de configuração precisamos inicializar o módulo MPU6050 e também podemos calcular o erro IMU que é um valor que é usado posteriormente ao calcular os ângulos corretos do 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)

Você pode encontrar mais detalhes sobre como o acelerômetro e o giroscópio MEMS funcionam aqui. Um tutorial dedicado para o MPU6050 será lançado em breve.

Em seguida, precisamos inicializar a comunicação de rádio, ativar os resistores pull-up internos do Arduino para todas as entradas digitais e definir os valores padrão iniciais para todas as variáveis.
// 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)

Na seção de loop comece lendo todas as entradas analógicas, mapeie seus valores de 0 a 1023 em valores de byte de 0 a 255 porque já definimos as variáveis ​​em nossa estrutura como bytes. Cada entrada é armazenada na variável de dados específica da estrutura.
// 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)

Devemos apenas observar que, como usamos os resistores de pull-up, as leituras dos pinos digitais são 0 quando os botões são pressionados.
// 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)

Então, usando a função radio.write(), nós simplesmente enviamos os valores de todos os 14 canais para o receptor.
// Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));Code language: Arduino (arduino)

Caso a chave seletora 1 esteja ligada, usamos os dados do acelerômetro e do giroscópio para o controle.
if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }Code language: Arduino (arduino)

Então, em vez dos valores de 1 X e Y do joystick, estamos usando os valores de ângulo que estamos obtendo da IMU, que anteriormente os convertemos de valores de -90 a +90 graus em valores de byte de 0 a 255 apropriadamente.
// 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)

Então é assim que o código do transmissor, as coisas mais importantes foram definir a comunicação de rádio e enviar os dados para o receptor.

Aqui está o código Arduino completo para este DIY Arduino RC Transmitter:
/*
        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 do receptor


Agora vamos dar uma olhada em como podemos receber esses dados. Aqui está um esquema simples do receptor Arduino e NRF24L01. Claro que você pode usar qualquer outra placa Arduino.

E aqui está um código receptor simples onde receberemos os dados e simplesmente imprimiremos no monitor serial para sabermos que a comunicação funciona corretamente. Novamente precisamos incluir a biblioteca RF24 e definir os objetos e a estrutura da mesma forma que no código do transmissor. Na seção de configuração ao definir a comunicação de rádio, precisamos usar as mesmas configurações do transmissor e definir o módulo como receptor usando a função 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)

No loop principal, usando a função available(), verificamos se há dados de entrada. Se true, simplesmente lemos os dados e os armazenamos nas variáveis ​​da estrutura. Agora podemos imprimir os dados no monitor serial para verificar se a transmissão funciona corretamente. Também usando a função millis() e uma instrução if verificamos se continuamos recebendo dados, ou se não recebemos dados por um período maior que 1 segundo, então redefinimos as variáveis ​​para seus valores padrão. Usamos isso para evitar comportamentos indesejados, por exemplo, se um drone acelera e perdemos a conexão, ele pode continuar voando, a menos que redefinamos os valores.

Então é isso. Agora podemos implementar este método de recebimento de dados para qualquer projeto Arduino. Por exemplo aqui o código para controlar o carro robô Arduino de um dos meus vídeos anteriores.

Como uma atualização para este projeto, eu fiz um receptor RC baseado em Arduino dedicado. Novamente, é baseado na mini placa Arduino Pro e possui várias conexões de servos e ESCs prontas para uso, colocadas em uma PCB compacta.

Controle sem fio do carro robô Arduino usando transmissor RC


Código Arduino:

Aqui precisamos definir as bibliotecas, a estrutura e a comunicação de rádio como explicado anteriormente. Então, no loop principal, precisamos apenas ler os dados recebidos e usar qualquer um deles para o que quisermos. Neste caso eu uso os valores do joystick 1 para dirigir o carro.

Arduino Ant Robot / Hexapod controle usando o Arduino RC Transmitter


Código Arduino:

Exatamente da mesma forma que fiz o Arduino Ant Robot do meu vídeo anterior para ser controlado sem fio usando este Arduino RC Transmitter. Só precisamos ler os dados e, de acordo com eles, executar as funções apropriadas, como avançar, esquerda, direita, mordida, ataque e assim por diante.

ESC e servocontrole usando transmissor RC


Por fim, vamos dar uma olhada em como este transmissor pode ser usado para controlar dispositivos RC comerciais.

Normalmente para esses dispositivos precisamos controlar seus servos ou motores brushless. Então, após receber os dados do transmissor, para controlar o servo simplesmente usamos a biblioteca Arduino Servo e usamos valores de 0 a 180 graus. Para controlar o motor brushless usando ESC, podemos novamente usar a biblioteca servo para gerar o sinal PWM de 50Hz usado para controlar o ESC. Variando o ciclo de trabalho de 1000 a 2000 microssegundos, controlamos a RPM do motor de zero ao máximo. However, more on controlling brushless motors using ESC in my next tutorial.

Please note that we actually cannot bind the standard RC receiver system with this NRF24L01 2.4GHz system. Instead, we need to modify or create our own receiver consisting of an Arduino and NRF24L01 Module. From there we can than generate the appropriate PWM or PPM signals for controlling the RC device.
/*
    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. Espero que tenham gostado deste vídeo e aprendido algo novo. Sinta-se à vontade para fazer qualquer pergunta na seção de comentários abaixo e confira minha Coleção de projetos do Arduino.

Processo de manufatura

  1. Kazoo
  2. DIY LUMAZOID Arduino Music Visualiser
  3. Faça uma máquina de escrever trabalhos de casa DIY em casa
  4. Faça você mesmo voltímetro usando Arduino e Smartphone
  5. Arduino + ESP Weather Box
  6. Faça você mesmo skate de realidade virtual
  7. Faça você mesmo Arduino RADIONICS Tratamento MMachine
  8. Simulador de corrida de movimento 2D DIY
  9. Ideia DIY com RFID
  10. DIY 3 eixos CNC VMC