Jun 05, 2017
Andrew Barbosa
It’s been a long time since anyone has worked on the RC Car project here in the Workshop and since I’m new to this project I figured now is a great time to begin simplifying and streamlining the wiring. The way everything was wired previously was great for prototyping but it left something to be desired for a more polished product. A lot of the wiring had gotten messed up from moving the bikes and just leaving the project unused for so long, so I grabbed a multimeter and began the work by checking all the connections. Previously a breadboard was used to send power to the bikes and also serve as a hub point to read the data from. This created a mess of wires that made it difficult to see how things connect and so I soldered up all the power lines and ground lines and added on a male pin. Now they can be directly connected to the 5v and GND pins on the Arduino itself. I then added male pins to each of the three signal wires so that they too could be plugged directly into the Arduino. With this new setup, I could eliminate the breadboard which cleaned up things nicely. Now that the connections were simplified I verified that everything was working and turned my attention to the RC car itself. When I began working on the car nothing seemed to be responsive. So, I decided to dissemble the system and redo it, following the same guidelines used previously, which fixed the issues. Now both Arduinos are communicating correctly and everything seems to be working except for the throttle which is glitchy at best. Once the receiver side is fully functional I’ll streamline the wiring and clean it up. Things on the to-do list for this project now are:
- Fix Throttle response
- Clean wiring on receiver side
- Add buttons to enable reverse mode
- Reimplement the FPV system
Once all these are done I’ll be designing a PCB that will condense everything and make the project more professional. Below you’ll find the current versions of the code being used on the project.
TRANSMITTER CODE:
#include <Adafruit_9DOF.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <SPI.h> //SPI library to communicate with the nRF24+
#include "RF24.h" // Download and Install (See above)
#include "printf.h" // Needed for "printDetails" Takes up some memory
#define CE_PIN 7 // The pins to be used for CE and SN
#define CSN_PIN 8
/* Assign a unique ID to the sensors */
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);
RF24 radio(CE_PIN, CSN_PIN);
byte addresses[][6] = {"1Node", "2Node"}; // These will be the names of the "Pipes"
unsigned long timeNow; // Used to grab the current time, calculate delays
unsigned long started_waiting_at;
boolean timeout; // Timeout? True or False
// Allows testing of radios and code without Joystick hardware. Set 'true' when joystick connected
//boolean hasHardware = false;
boolean hasHardware = true;
struct dataStruct {
unsigned long _micros; // to save response times
int throttle; //
int handBreak;
int bikeTilt;
int alignment; //steering trim
int headpitch; //pitch of the camera mount
int headroll; //roll of camera mount
int heading; //yaw of the camera mount
bool ModeSwitch; // centering switch
} myData; // This can be accessed in the form: myData.Xposition etc.
void setup() /****** SETUP: RUNS ONCE ******/
{
Serial.begin(115200);
Serial.println(F("Lets send this data"));
printf_begin(); //uncomment for debug info
pinMode(6, INPUT); // switch for drive mode
pinMode(4, INPUT); //the radio channel switch
pinMode(9, OUTPUT); // power led
/* Initialise the sensors */
accel.begin();
mag.begin();
radio.begin(); // Initialize the nRF24L01 Radio
if (digitalRead(4) == HIGH)
{
radio.setChannel(106); // set to channel 1
}
else
{
radio.setChannel(120); // set to channel 2
}
radio.setDataRate(RF24_250KBPS);
// Set the Power Amplifier Level low to prevent power supply related issues since this is a
// getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
// PALevelcan be one of four levels: RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH and RF24_PA_MAX
radio.setPALevel(RF24_PA_HIGH);
// radio.setPALevel(RF24_PA_MAX);
// Open a writing and reading pipe on each radio, with opposite addresses
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1, addresses[1]);
// Start the radio listening for data
radio.startListening();
radio.printDetails(); //Uncomment to show debugging information
}
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
digitalWrite(9, HIGH); //turn on the power led
sensors_event_t accel_event;
sensors_event_t mag_event;
sensors_vec_t orientation;
accel.getEvent(&accel_event);
mag.getEvent(&mag_event);
radio.stopListening(); // First, stop listening so we can talk.
if (hasHardware) // Set in variables at top
{
myData.throttle = analogRead(A0);
myData.alignment = analogRead(A1);
myData.handBreak = analogRead(A2);
myData.bikeTilt = analogRead(A3);
myData.ModeSwitch = digitalRead(6);
myData.headroll = orientation.roll;
myData.headpitch = orientation.pitch;
myData.heading = orientation.heading;
}
//else
{
// myData.Lposition = 256; // Send some known fake data
// myData.Rposition = 512;
}
myData._micros = micros(); // Send back for timing
Serial.print("Throttle = ");
Serial.print(myData.throttle);
Serial.print("\t");
Serial.print("Hand Break = ");
Serial.print(myData.handBreak);
Serial.print("\t");
Serial.print("Bike Tilt = ");
Serial.print(myData.bikeTilt);
Serial.print("\t");
Serial.print(myData.heading);
Serial.print("\t");
Serial.println(myData.headpitch);
Serial.print(F("Now sending - "));
if (!radio.write( &myData, sizeof(myData) )) {
Serial.println(F("Transmit failed "));
}
radio.startListening();
started_waiting_at = micros(); // timeout period, get the current microseconds
timeout = false; // variable to indicate if a response was received or not
while ( ! radio.available() ) {
if (micros() - started_waiting_at > 200000 ) { // If waited longer than 200ms, indicate timeout and exit while loop
timeout = true;
break;
}
}
if ( timeout )
{ // Describe the results
Serial.println(F("Response timed out - no Acknowledge."));
}
else
{
// Grab the response, compare, and send to Serial Monitor
radio.read( &myData, sizeof(myData) );
timeNow = micros();
digitalWrite(2, HIGH);
// Show it
Serial.print(F("Sent "));
Serial.print(timeNow);
Serial.print(F(", Got response "));
Serial.print(myData._micros);
Serial.print(F(", Round-trip delay "));
Serial.print(timeNow - myData._micros);
Serial.println(F(" microseconds "));
}
// Send again after delay. When working OK, change to something like 100
delay(100);
}
void initSensors()
{
if(!accel.begin())
{
/* There was a problem detecting the LSM303 ... check your connections */
//Serial.println(F("Ooops, no LSM303 detected ... Check your wiring!"));
}
else
Serial.println("Somethings wrong");
if(!mag.begin())
{
/* There was a problem detecting the LSM303 ... check your connections */
Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
}
else
Serial.println("Somethings off");
}
RECIEVER CODE:
#include <SoftwareServo.h>
#include <SPI.h>
#include "RF24.h"
#define CE_PIN 7 // The pins to be used for CE and SN
#define CSN_PIN 8
RF24 radio(CE_PIN, CSN_PIN);
SoftwareServo steering;
SoftwareServo gogojuice;
SoftwareServo yaw;
SoftwareServo pitch;
SoftwareServo roll;
byte addresses[][6] = {"1Node", "2Node"}; // These will be the names of the "Pipes"
struct dataStruct {
unsigned long _micros;
int throttle; // The Joystick position values
int handBreak;
int bikeTilt;
int alignment;
int headpitch;
int headroll;
int heading;
bool ModeSwitch;
} myData; // This can be accessed in the form: myData.Xposition etc.
void setup()
{
Serial.begin(115200);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
pinMode(9, OUTPUT); //yaw
pinMode(6, OUTPUT); //Pitch
pinMode(10, OUTPUT); //Roll
// if (digitalRead(4) == HIGH)
// {
// radio.setChannel(106); // set to channel 1
// }
// else
// {
// radio.setChannel(120); // set to channel 2
// }
//
radio.begin(); // Initialize the nRF24L01 Radio
radio.setChannel(108);
radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_HIGH);
// Open a writing and reading pipe on each radio, with opposite addresses
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1, addresses[0]);
// Start the radio listening for data
radio.startListening();
steering.attach(3);
gogojuice.attach(5);
yaw.attach(9);
pitch.attach(6);
roll.attach(10);
gogojuice.write(40);
Serial.println("Setup Ran");
}
void loop()
{
digitalWrite(2,HIGH);
if ( radio.available())
{
while (radio.available()) // While there is data ready to be retrieved from the receive pipe
{
radio.read( &myData, sizeof(myData) ); // Get the data
}
radio.stopListening(); // First stop listening so we can transmit
radio.write( &myData, sizeof(myData) ); // Send the received data back.
radio.startListening(); // Now resume listening so we catch the next packet
}
double Mode = 0;
// if (true == myData.ModeSwitch)
// {
// Mode = 0.01;
// }
// else
// {
// Mode = 0;
// }
SoftwareServo::refresh();
int drive;
int offset = myData.alignment;
offset = map(offset, 0, 1023, -30, 30);
int bikeTiltRecieved = myData.bikeTilt;
int handBreakRecieved = myData.handBreak;
int throttleRecieved = myData.throttle;
int tilt = map(bikeTiltRecieved, 0, 1023, 0, 180);
tilt = tilt + offset;
if (throttleRecieved > 100 && handBreakRecieved < 100)
{
drive = 96 + throttleRecieved*Mode;
//drive = 96 + throttleRecieved;
}
if (throttleRecieved < 100 && handBreakRecieved > 100)
{
drive = 85;
//drive = 85 + throttleRecieved;
}
if (throttleRecieved > 100 && handBreakRecieved > 100)
{
drive = 90;
//drive = 96 + throttleRecieved;
}
if (throttleRecieved < 100 && handBreakRecieved < 100)
{
drive = 90;
//drive = 96 + throttleRecieved;
}
int PITCH = map (myData.headpitch, -180, 180, 0, 180);
int YAW = map(myData.heading, 0, 360, 0, 180);
steering.write(tilt);
gogojuice.write(drive);
yaw.write(YAW);
pitch.write(PITCH);
roll.write(90);
Serial.print("Throttle = ");
Serial.print(myData.throttle);
Serial.print("\t");
Serial.print("Hand Break = ");
Serial.print(myData.handBreak);
Serial.print("\t");
Serial.print("Bike Tilt = ");
Serial.print(myData.bikeTilt);
Serial.print("\t");
Serial.print(YAW);
Serial.print("\t");
Serial.println(PITCH);
}