RC Car Project Update



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.

-Andrew








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);
}

No comments:

Post a Comment