Introduction: Hand and Phone Controlled RC Car
What you need:
- RC Car (I used this one)
- Arduino Nano (Arduino)
- ESP8266 Wifi module (Sparkfun)
- 9DOF Gyrometer/Accelerometer/Magnetometer (Adafruit)
- 5V 4-Channel Relay Module (Amazon)
- Blynk App for iPhone/Android
- 2xAA Battery Pack(Amazon)
- 3.3V FTDI USB to TTL Serial Monitor(Amazon)
- Resistors(1K, 2K, 10K)
- Jumper Cables
Step 1: Reverse Engineering the Remote
I decided to control the RC car using the car's native controller, as opposed to say mounting an Arduino onto the car itself and using a motor shield to power the car.
For this controller, all it had was 4 switches that complete the circuit to cause the car to travel forward/back or to turn the wheels left/right.
I simply soldered 4 pairs of wires to control the Forward/Back/Left/Right controls, with one wire connecting to the circular bottom lead and the other soldered onto the flexible metal strip, as seen in the second picture.
These 4 pairs were later connected to the relay.
Step 2: The Relay
Next up is connecting the wires we just soldered to the relay. Because the controls are simply completing a circuit, it does not matter which wire you connect to where in the relay, so simply wire up each directional pair to a pair on the relay. I used the middle and right pin from each set of three on the relay. I wired the relay to the Arduino Nano as also depicted by the diagram.
Step 3: Gyrometer and Accelerometer
Surprisingly, this was one of the easier portions of the project. I wired the module to the Nano using this guide on Adafruit's website, and really all I had to wire was the 3V3 to 3V3, Ground to Ground, SCL to A5 and SDA to A4. For the code, I used the four drivers located on Adafruit's site. Thankfully, these libraries convert the raw data from the sensors into pitch/roll/yaw data, which gives you easy access to usable data without having to figure out any equations or to manipulate the data.
If the code below is formatted incorrectly, here is a link to the github containing all the code.
<p>#include <Wire.h><br>#include <Adafruit_Sensor.h> #include <Adafruit_LSM303_U.h> #include <Adafruit_L3GD20_U.h> #include <Adafruit_9DOF.h></p><p>Adafruit_9DOF dof = Adafruit_9DOF(); Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(30301); Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(30302);</p><p>int frontPin = 3; int backPin = 4; int leftPin = 5; int rightPin = 6; #define ON 0 #define OFF 1</p><p>float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;</p><p>boolean right; boolean left; boolean forward; boolean back;</p><p>void initSensors() { if(!accel.begin()) { Serial.println(F("Ooops, no LSM303 detected ... Check your wiring!")); while(1); } if(!mag.begin()) { Serial.println("Ooops, no LSM303 detected ... Check your wiring!"); while(1); } }</p><p>void relay_init(void)//initialize the relay { //set all the relays OUTPUT pinMode(frontPin, OUTPUT); pinMode(backPin, OUTPUT); pinMode(leftPin, OUTPUT); pinMode(rightPin, OUTPUT); relay_SetStatus(OFF,OFF,OFF,OFF);//turn off all the relay }</p><p>void relay_SetStatus( unsigned char status_1, unsigned char status_2, unsigned char status_3,unsigned char status_4) { digitalWrite(frontPin, status_1); digitalWrite(backPin, status_2); digitalWrite(leftPin, status_3); digitalWrite(rightPin, status_4);</p><p>}</p><p>void setup() { Serial.begin(115200); initSensors(); relay_init();</p><p>}</p><p>void loop(void) {</p><p> /* relay_SetStatus(ON, OFF, OFF,OFF);//turn on RELAY_1 delay(2000);//delay 2s relay_SetStatus(OFF, ON, OFF,OFF);//turn on RELAY_2 delay(2000);//delay 2s relay_SetStatus(OFF, OFF, ON,OFF);//turn on RELAY_3 delay(2000);//delay 2s relay_SetStatus(OFF, OFF, OFF,ON);//turn on RELAY_3 delay(2000);//delay 2s */ sensors_event_t accel_event; sensors_event_t mag_event; sensors_vec_t orientation;</p><p> accel.getEvent(&accel_event); if (dof.accelGetOrientation(&accel_event, &orientation)) { Serial.print(F("Roll: ")); Serial.print(orientation.roll); Serial.print(F("; ")); Serial.print(F("Pitch: ")); Serial.print(orientation.pitch); Serial.println(F("; ")); } if(orientation.roll > 25){ right = true; left = false; }else if(orientation.roll < -25){ right = false; left = true; }else{ right = false; left = false; } if(orientation.pitch > 25){ forward = true; back = false; }else if(orientation.pitch < -25){ forward = false; back = true; }else{ forward = false; back = false; }</p><p> if(right){ digitalWrite(rightPin, ON); digitalWrite(leftPin, OFF); }else if(left){ digitalWrite(rightPin, OFF); digitalWrite(leftPin, ON); }else{ digitalWrite(rightPin, OFF); digitalWrite(leftPin, OFF); } if(forward){ digitalWrite(frontPin, ON); digitalWrite(backPin, OFF); }else if(back){ digitalWrite(frontPin, OFF); digitalWrite(backPin, ON); }else{ digitalWrite(frontPin, OFF); digitalWrite(backPin, OFF); } }</p>
Step 4: The Tricky ESP8266 Module
I'm not gonna lie, this module is real pain in the *** to work with. That being said, for the price you get some pretty insane functionality, so it's still worth it to figure out how to get it to work. For me, my problem is that I had to change the baud rate of the chip from 115200 to 9600, but for some reason the baud rate would reset back to 115200 whenever it was unplugged.
I used Abhinaba Basu's great guide here, which is where the two wiring diagrams for connecting the ESP module to the FTDI board and the nano come from. It's important to note that the 3.3V Power does not come from the Nano, but from an external 2xAA battery pack.
I was able to fix the baud rate by sending the command AT+UART_DEF=9600,8,1,0,0. However, this was very fickle for me, and many of the online resources I used said that the command to use was AT+CIOBAUD=9600. This would work for me, however it would reset the baud rate back to 115200 whenever it was reset.
Step 5: Blynk App + Code
The Blynk App is actually fairly simple to use. After downloading it to your phone, You set up a project that uses an Arduino Nano and add a Joystick to the project. The settings should be the same as those in the picture.
The code is actually simpler using this than it is for using the 9DOF Sensor, however you will still need to download the library for the ESP8266 module from Blynk. Also, be sure to enter in the Blynk Auth Token(Found in the app) and the name/password to your wifi.
HERE is also a link to the github containing all the code in case the code below does not work.
<p>#define BLYNK_PRINT Serial // Comment this out to disable prints and save space<br>#include <ESP8266_Lib.h> #include <BlynkSimpleShieldEsp8266.h></p><p>// You should get Auth Token in the Blynk App. // Go to the Project Settings (nut icon). char auth[] = "AUTH TOKEN";</p><p>// Your WiFi credentials. // Set password to "" for open networks. char ssid[] = "WIFI NAME"; char pass[] = "WIFI PASS";</p><p>// Hardware Serial on Mega, Leonardo, Micro... //#define EspSerial Serial</p><p>// or Software Serial on Uno, Nano... #include SoftwareSerial EspSerial(8, 9); // RX, TX</p><p>// Your ESP8266 baud rate: #define ESP8266_BAUD 9600</p><p>ESP8266 wifi(&EspSerial);</p><p>int frontPin = 3; int backPin = 4; int leftPin = 5; int rightPin = 6; #define ON 0 #define OFF 1 boolean right; boolean left; boolean forward; boolean back; int turnValue; int speedValue;</p><p>void relay_SetStatus( unsigned char status_1, unsigned char status_2, unsigned char status_3, unsigned char status_4) { digitalWrite(frontPin, status_1); digitalWrite(backPin, status_2); digitalWrite(leftPin, status_3); digitalWrite(rightPin, status_4);</p><p>}</p><p>void relay_init(void)//initialize the relay { //set all the relays OUTPUT pinMode(frontPin, OUTPUT); pinMode(backPin, OUTPUT); pinMode(leftPin, OUTPUT); pinMode(rightPin, OUTPUT); relay_SetStatus(OFF, OFF, OFF, OFF); //turn off all the relay }</p><p>void setup() { // Set console baud rate Serial.begin(9600); relay_init(); delay(10); // Set ESP8266 baud rate EspSerial.begin(ESP8266_BAUD); delay(10);</p><p> Blynk.begin(auth, wifi, ssid, pass); }</p><p>BLYNK_WRITE(V0){ turnValue = param[0].asInt(); speedValue = param[1].asInt(); if (turnValue == 2) { right = true; left = false; } else if (turnValue == 0) { right = false; left = true; } else { right = false; left = false; } if (speedValue == 0) { forward = true; back = false; } else if (speedValue == 2) { forward = false; back = true; } else { forward = false; back = false; }</p><p> if (right) { digitalWrite(rightPin, ON); digitalWrite(leftPin, OFF); } else if (left) { digitalWrite(rightPin, OFF); digitalWrite(leftPin, ON); } else { digitalWrite(rightPin, OFF); digitalWrite(leftPin, OFF); }</p><p> if (forward) { digitalWrite(frontPin, ON); digitalWrite(backPin, OFF); } else if (back) { digitalWrite(frontPin, OFF); digitalWrite(backPin, ON); } else { digitalWrite(frontPin, OFF); digitalWrite(backPin, OFF); } } void loop() { Blynk.run(); }</p>
Step 6: Enjoy!!!
In the future I plan on making the hand controlled apparatus much more appealing, possibly by 3D printing an actual arm holder for it and cleaning up the wires, but for a prototype it's not too shabby at all.