O rádio controle é amplamente utilizado em hobbies e é muito conhecido por todos nós.
Sabe aquele carrinho de controle que você teve ou aquele drone que você viu voando? Ambos são controlados por um rádio controle e tem o princípio de funcionamento idêntico, apesar das diferenças de tecnologia. Vejamos abaixo algumas características:
Os canais são, a grosso modo, os comandos ou funções que o rádio nos permite ter. São usados para controlar a direção, velocidade e funções extras que o dispositivo controlado necessita em sua operação. A maioria dos rádio controles que temos hoje em dia tem pelo menos 6 canais, sendo 4 principais e 2 destinados a funções extras.
O dispositivo recebe esse nome por funcionar através de radiofrequência, onde a comunicação entre transmissor e receptor é feita atualmente na casa dos 2.4 GHz. Essa tecnologia chegou para substituir os tradicionais rádios de 72 MHz que sofriam com interferências de outros dispositivos atuando na mesma frequência. Quem nunca teve um carrinho de controle e sofreu interferência quando um colega estava brincando com outro carrinho nas proximidades, não é? Essa mudança de tecnologia fez com que os rádios de hoje sejam muito mais confiáveis e tenham um alcance considerável, sendo possível chegar na a vários quilômetros dependendo do local e da qualidade do transmissor.
O receptor é o responsável por receber e repassar os comandos que o usuário quer aplicar a um determinado dispositivo. Esses comandos são enviados através de pulsos, normalmente PWM, que são destinados a controlar o ângulo de um servo motor ou a velocidade de um motor, estando este conectado a um ESC.
Agora, melhor que somente entender os detalhes e características de um equipamento tão sofisticado e relativamente caro é poder construir e adaptar um de acordo com sua necessidade e com um custo bem reduzido. Pensando nisso, vamos te ensinar como montar o seu próprio rádio controle baseado no Arduino. Veja só:
- 1x Pro Mini Atmega328p 5V 16MHz
- 1x Módulo Wireless NRF24L01 + Antena 1km
- 1x Acelerômetro e Giroscópio 3 Eixos 6 DOF MPU6050 – GY-521
- 1x Placa Fenolite Perfurada 10x15cm
- 1x Adaptador Bateria 9V sem Plug
- 1x Micro Chave SS12D00G4 – 3 terminais – 4mm
- 1x Regulador de tensão AM1117 3,3V
- 1x Capacitor Eletrolítico 100uF x 16V
- 1x Capacitor Disco Cerâmico 100nF x 50V
- 2x Módulo Joystick Analógico para Arduino – KY-023
- 2x Chave Alavanca – 3 Posições 3 Terminais
- 2x Potenciômetro 1KΩ
- 4x Push Button (Chave Táctil) 2 pinos
- 1x bateria 9V
- 1x Arduino Pro Mini
- 1x Módulo Wireless NRF24L01 + Antena 1km
- 1x regulador de tensão AM1117 3,3V
- 1x Capacitor 0,1uF
- 1x Placa Fenolite Perfurada 7x5cm
- 1x capacitor 100uF
Antes de prosseguirmos, vamos apresentar alguns componentes novos de forma bem resumida:
O NRF24L01 é um transceptor, ou seja, é um componente que pode funcionar como transmissor e receptor. Essa configuração nos permite dois tipos de comunicação: a unidirecional, onde temos um transmissor e um receptor fixos, e a bidirecional, onde ambos os lados podem transmitir e receber dados. Suas características incluem a tecnologia 2.4 GHz, baixo consumo de energia, potência do sinal considerável e velocidade de transmissão na casa dos 250Kbps. O módulo que utilizaremos é o NRF24L01+PA+LNA, que possui um amplificador de sinal e uma antena de 2dBi, que nos permite alcançar, segundo o fabricante, distâncias de até 1Km em locais abertos e livres de obstáculos que possam vir a bloquear o sinal.
O módulo MPU6050 é um sensor que possui um acelerômetro e um giroscópio em seu integrado. Cada um desses sensores retorna valores em ângulos nos eixos X, Y e Z correspondentes à movimentação e inclinação de objetos tridimensionais. No nosso projeto, ele será utilizado visando projetos futuros baseados em controle por gestos.
É basicamente um Arduino Uno em miniatura. Possui o mesmo microcontrolador e especificações bem semelhantes. Para saber mais, visite o guia completo sobre ele clicando aqui.
A montagem, apesar de ter muitas conexões, é bem simples e fácil de entender, basta acompanhar os diagramas e não terá dificuldades. Veja só:
Passo 1 – Soldagem dos terminais
Para a montagem do transmissor, vamos começar preparando os componentes. É necessário soldar pinos em todos eles para facilitar a montagem. Também precisamos trocar os pinos em 90° do módulo Joystick pelos de 180°, para facilitar o encaixe na placa perfurada.
IMPORTANTE: Alguns joysticks não possuem ilhas de solda na parte superior, o que requer um pouco mais de cuidado e atenção na hora de realizar o processo. Será necessário utilizar um suporte para segurar o módulo e a barra de pinos, para que a soldagem seja realizada por baixo, conforme a foto:
Também recomendamos que remova a parte plástica que envolve os pinos após a solda, ficando dessa forma:
Passo 2 – Organização dos componentes na placa
Após essa etapa, vamos posicionar os componentes de forma que fiquem confortáveis nas nossas mãos. Tiramos por base a posição dos sticks e chaves de um rádio controle profissional, já que as chaves auxiliares e potenciômetros estão numa posição de fácil acesso sem que seja necessário soltar os sticks.
Passo 3 – Soldagem dos componentes
Depois de posicionar os componentes, podemos dar início ao processo de soldagem dos mesmos, atentando sempre para não exagerar na solda e unir dois terminais
Passo 4 – Conexões e trilhas
Com os componentes já soldados na placa, vamos iniciar as ligações de alimentação e dados. Para isso, você deve seguir fielmente as conexões apresentadas no diagrama abaixo e estude a melhor posição para se fazer as trilhas.
Créditos: howtomechatronics.com
Recomendamos que façam as trilhas de alimentação primeiro, respeitando sempre as tensões e polaridades. Isso garantirá que você não vai esquecer de alimentar nada no circuito!
Note também que soldamos o regulador de tensão bem próximo ao módulo NRF24L01edr4, pois somente ele usará a tensão de 3,3V em todo o projeto. Lembre-se também de soldar respectivos os capacitores conforme indicado no diagrama.
Após isso, basta consultar o esquemático e fazer todas as conexões com os pinos digitais e analógicos do Arduino.
Passo 5 – Teste
Esse passo é extremamente importante para que você possa verificar erros de conexão que possam ter passado despercebido e evite uma dor de cabeça maior ainda no decorrer da montagem. Para isso, pegue um multímetro e posicione na escala de continuidade. Faça os testes de ponto em ponto, verificando se existe conexão e nenhum terminal está em curto. Para os pontos em comum (GND e VCC), escolha um único ponto e verifique se existe conexão entre ele e os demais de mesma polaridade, assim você garante que tudo está alimentado corretamente.
Passo 6 – Programação
Com todos os testes de continuidade feitos, vamos passar para a programação. Como o Arduino Pro Mini não possui interface USB, vamos precisar de um Arduino Uno ou um conversor USB serial. Se você não sabe como programar esse arduino, sugerimos que acesse nosso post sobre o mesmo clicando aqui.
O código que vamos utilizar foi desenvolvido por Dejan Nedelkovsk e faz uso da biblioteca RF24, você pode acessar o Github dela e fazer o download clicando nesse link.
/* 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(A2), 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(A1), 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); }
Créditos: Dejan Nedelkovski, www.HowToMechatronics.com
O funcionamento do código está descrito nos comentários ao longo do mesmo e também nas referências do post.
Para carregar o código, selecione a opção “Arduino Pro or Pro Mini”, selecione a porta COM e faça o envio.
Feito isso, você já pode cuidar da montagem do receptor. Veja só:
O receptor, como descrito acima, é a peça que distribui os comandos enviados pelo transmissor, sem ele nada pode ser controlado e por isso também vamos montar um para o nosso transmissor. Ele possuirá 9 canais que podem ser programados de acordo com a sua necessidade.
Passo 1 – Soldagem
Como primeiro passo, você deve soldar todos os pinos do Arduino, preparando-o para o próximo passo.
Passo 2 – Organização dos componentes na placa
Nessa parte, vamos precisar de:
– 3 barras com 8 pinos;
– 2 barras com 3 pinos;
– 1 barra com 6 pinos.
– 1 barra com 3 pinos
– 1 barra com 2 pinos
São elas que permitirão todas as conexões de sinal e alimentação com o receptor.
Para a organização na plaquinha, sugerimos que siga o padrão abaixo:
Créditos: howtomechatronics.com
Passo 3- Soldagem dos componentes:
O processo aqui será o mesmo do transmissor, mantendo as recomendações referentes às trilhas de alimentação e ao regulador de tensão do módulo RF, lembrando sempre de seguir o diagrama abaixo:
Créditos: howtomechatronics.com
IMPORTANTE: Coloque jumpers entre os contatos dos canais 7 e 8, pois são ligados aos pinos TX e RX do Arduino, o que pode causar alguma falha na hora da programação caso estejam conectados.
Passo 4 – Trilhas e Conexões:
Aqui novamente você deve seguir o diagrama esquemático do receptor, para que não haja ligações erradas e seu dispositivo apresente um mal funcionamento.
Passo 5 – Teste
Novamente recomendamos que você faça os testes de continuidade já feitos no transmissor. Você deve garantir que não exista nenhum curto circuito entre os pinos e que isso venha causar algum dano ao receptor ou aos componentes conectados a ele.
Passo 6 – Programação
O processo de programação do receptor é o mesmo que foi descrito para o transmissor, basta carregar no Arduino e não terá problemas. As explicações você também encontra ao longo do código e nas referências do post.
/* Arduino RC Airplane == Receiver Code = by Dejan, www.HowToMechatronics.com Library: TMRh20/RF24, https://github.com/tmrh20/RF24/ */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Servo.h> #define led 9 RF24 radio(3, 2); // nRF24L01 (CE, CSN) const byte address[6] = "00001"; unsigned long lastReceiveTime = 0; unsigned long currentTime = 0; Servo throttle; // create servo object to control the ESC Servo rudderServo; Servo elevatorServo; Servo aileron1Servo; Servo aileron2Servo; int throttleValue, rudderValue, elevatorValue, aileron1Value, aileron2Value, travelAdjust; // 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_MAX); radio.startListening(); // Set the module as receiver resetData(); throttle.attach(10); rudderServo.attach(4); // CH1 elevatorServo.attach(5); // CH2 aileron1Servo.attach(6); // CH3 aileron2Servo.attach(7); // CH4 pinMode(led, OUTPUT); // CH6 } 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 throttle - brushless motor with ESC throttleValue = constrain(data.j1PotY, 80, 255); // Joysticks stays in middle. So we only need values the upper values from 130 to 255 throttleValue = map(throttleValue, 80, 255, 1000, 2000); throttle.writeMicroseconds(throttleValue); // Adjusting the servos responsiveness travelAdjust = map(data.pot2, 0, 255, 0, 25); // Elevator control elevatorValue = map(data.j2PotY, 0, 255, (85 - travelAdjust), (35 + travelAdjust)); elevatorServo.write(elevatorValue); // Ailerons control aileron1Value = map(data.j2PotX, 0, 255, (10 + travelAdjust), (80 - travelAdjust)); aileron1Servo.write(aileron1Value); aileron2Servo.write(aileron1Value); // Rudder trimming function if (data.j1PotX > 127) { aileron1Value = data.pot1 + (data.j2PotX - 127); } if (data.j1PotX < 127) { aileron1Value = data.pot1 - (127 - data.j2PotX); } // Rudder control rudderValue = map(rudderValue, 0, 255, (10 + travelAdjust), (90 - travelAdjust)); rudderServo.write(rudderValue); // Monitor the battery voltage int sensorValue = analogRead(A3); float voltage = sensorValue * (5.00 / 1023.00) * 3; // Convert the reading values from 5v to suitable 12V i // If voltage is below 11V turn on the LED if (voltage < 11) { digitalWrite(led, HIGH); } else { digitalWrite(led, LOW); } } void resetData() { // Reset the values when there is no radio connection - Set initial default values data.j1PotX = 127; data.j1PotY = 80; // Motors stops // the central point of the joystick is not starting point for the throttle, its at value of 80 instead of 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; }
Créditos: Dejan Nedelkovski, www.HowToMechatronics.com
Se você chegou aqui, seu rádio controle já está pronto para funcionar. Sugerimos que passe uma fita isolante sobre as conexões para garantir que nenhuma se solte e posicione a bateria do transmissor em um local fixo, usando fita dupla-face. Feito isso, está tudo pronto para iniciar os testes e aplicações.
Para testar, conectamos o receptor a um automodelo elétrico, sendo a direção no canal 1 e o ESC no canal 9 do receptor.
Veja só um vídeo do funcionamento do nosso rádio controle:
Com esse sistema montado vamos iniciar uma série de projetos rádio controlados, visando entreter, conhecer e desenvolver novos projetos relacionados ao fascinante mundo da programação e eletrônica proporcionados pelo Arduino. Você também pode alterar o projeto e os códigos de acordo com a necessidade. Sua imaginação é o limite!!
https://howtomechatronics.com/projects/diy-arduino-rc-transmitter/
https://howtomechatronics.com/projects/diy-arduino-rc-receiver/
https://howtomechatronics.com/projects/arduino-rc-airplane-diy/
Gostou do projeto e também construiu o seu? Fez adaptações e conseguiu resultados melhores ainda? Tire uma foto e nos marque no Instagram @eletrogate.
Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!