Autonomous RC car guided by GPS coordinates - project thread

In the DARPA grand challenge, full-size, un-manned vehicles were tasked with following a route in the desert described by GPS coordinates (DARPA Grand Challenge - Wikipedia). I thought it would be interesting to do the same thing, but with a radio-controlled car (in my case, a Traxxas Slash 5803). To make the car drive autonomously, the radio controller would be replaced with a micro-controller.

To do this, I will need to:

Current outstanding questions are:

  • Which proximity sensor should I choose to avoid crashes?
  • What crash prevention algorithm should I use?

Thanks to esawdust for his helpful guide (http://www.esawdust.com/blog/autveh/files/AutonomousRC-part1.html)


www.jeffsinventions.com

Replacing radio control with micro-controller control
How does the radio controller communicate with the speed control?
To figure this out, I spliced into the wiring between the radio receiver and the speed control and read the signal between the ground (black) and the control wire (white).

In all cases, the wave form was 3.2 V high. They were 10 ms apart. Thanks to (Rigol DS1052E Oscilloscope) for a good tutorial on taking screen shots with my oscilloscope, a Rigol DS1052E.

At 100% reverse, the wave form was 1 ms wide.

At neutral, the wave form was 1.5 ms wide.

At 100% forward, the wave form was 2 ms wide.

How can I imitate the radio receiver's signal with a micro-controller?
How can I specify the signal's height?
I need to step down the 5 V output from the micro-controller to the 3.2 V signal accepted by the speed control. To do this, I used a voltage divider (Voltage divider - Wikipedia).

Vout/Vin = R2/(R1+R2)
or, R1 = (Vin*R2)/Vout - R2
In my case,
Vin = 5 V
R2 = 2000 ohms
Vout = 3.2 V
so, R1 = 1125 ohms

How can I specify the signal's frequency?
To specify the signal's pulse width and frequency, I used the servo library (Servo - Arduino Reference). However, by default, the servo library has one cycle per 20 ms, as against the one cycle per 10 ms required by my speed control. To change the frequency, I followed the advice here (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1251751699). I went to the servo library in notepad (in my case, it was in C:\Program Files\arduino-1.0\libraries\Servo\Servo.h). I changed the following line from:

#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
TO
#define REFRESH_INTERVAL 10000 // minumim time to refresh servos in microseconds

How can I specify the signal's pulse width?
While I was in the configuration file, I noticed that it had minimum and maximum pulse widths that were also different from my speed control. I changed them to better match:

#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
TO
#define MIN_PULSE_WIDTH 1000 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2000 // the longest pulse sent to a servo

I then tried out the library with the Sweep example (http://arduino.cc/en/Tutorial/Sweep), which moves the motor from 100% reverse to 100% forward to 100% reverse and so on.

Getting around throttle neutral protection
When I tried it at first, the green light on the speed control flashed and the motor didn't spin. By looking at the manual, I saw that this indicated that "throttle neutral protection" was activated. This means that the speed control will not engage the motor until the throttle spends a while in the neutral position (http://traxxas.com/sites/default/files/3018R_KC1306-R00%20XL-5%20LVD%20Addm.pdf)

To get around this, I tried switching the starting state from 0 degrees (1000 microsecond pulse width) to 90 degrees (1500 microseconds). I ran into the same issue. So, I gave it 10 seconds in neutral before accelerating to 100% forward. Finally, the motor would spin.

Preventing the car from crashing
How can I add manual over-ride?
In order to take control if my car is on its way to trouble, I wanted to setup my car such that if it detects input from the remote control, it will obey that input. If it does not detect that input, it will continue to operate autonomously.

How should I wire the arduino such that it detects the signal from the radio receiver?
After unsuccessfully trying to use a range of rc car receiver reading libraries (e.g., servodecode), I ended up getting PPMrcin (GitHub - domenicomonaco/PPM-Signal-Reader-ARDUINO: Arduino PPM signal reader/decoder Library) to work. To do the wiring, I used this tutorial: http://pillsofbits.com/project/libreria-di-arduino-leggere-segnali-ppm.

How should I code the arduino such that it detects the signal from the radio receiver?
To get the library working, I had to change the references from Wprogram.h to Arduino.h in the files PPMrcIn.cpp and PPMrcIn.h. I also had to install the Statistic library (GitHub - domenicomonaco/Arduino-Statistic-Library: Simple Statistic Library).

How should I code the arduino such that manual over-ride works?
If the basic idea is that the car will operate autonomously unless it receives input from the radio receiver, then I need to write some code that will detect whether or not input is received and, if so, to pass that input to the car's speed control.

This is what I came up with. It worked great for my purposes.

// Adapted from:

//
// ReadSignalFromRC.pde
// Example for PPMrcIn Arduino Library
//
// Created by Domenico Monaco on 20/11/2011
// Copyright 2011 Domenico Monaco - domenico.monaco@kiuz.it
//
// License: GNU v2
//

// Also

// Sweep
// by BARRAGAN http://barraganstudio.com
// This example code is in the public domain.

// include libraries & initialize class for reading signal
#include <PPMrcIn.h>
#include <Statistic.h>
Channel channel1;

// include libraries & initialize class for sending signal
#include <Servo.h>
Servo myservo;
int pulseWidth;

// specify discrepancy between pulse width received and sent
// and receiver neutral range

int receiveSendOffset = 50;
int receiverSignal;
int neutralMin = 1480;
int neutralMax = 1520;

void setup() {
Serial.begin(9600);

// prepare reading of receiver
Serial.println("Ready:");
pinMode (13, INPUT);
channel1.init(1,13);

// prepare writing of speed control
myservo.attach(9);
delay(5000);
}

void loop() {
// read the receiver signal
channel1.readSignal();

receiverSignal = channel1.getSignal() + receiveSendOffset;

// if the receiver signal is neutral, then let the car drive itself
if(receiverSignal >= neutralMin && receiverSignal <= neutralMax)
{
Serial.println(receiverSignal);
Serial.println("Automatic");
myservo.write(1500);
delay(1000);
}

// if the receiver signal is not neutral, then let the driver drive the car
else
{
Serial.println(receiverSignal);
Serial.println("Manual");
myservo.write(receiverSignal);
delay(1000);
}

Thanks. That looks like a great class. I look forward to enrolling the next time its offered.

Hi,
You might find something useful on my blog such as -

or this -

This one gives you a simple way to toggle something on and off using your existing equipment, I use it to turn child mode on and off, you could use it to turn manual/auto on and off

Duane B

rcarduino.blogspot.com

Thanks for the link, DuaneB.


Here is an outline of how I will make the car avoid obstacles while maintaining its heading towards its next GPS point.

  • I will mount an ultrasonic sensor and a compass on a servo in front of the car that sweeps 180 degrees back and forth (http://www.parallax.com/Portals/0/Downloads/docs/prod/robo/570-28015-PingBracket-v2.0.pdf).
  • Every couple of degrees, it will record the compass heading and the distance.
  • After completing the sweep, it will and choose the heading with a distance greater than two feet and a heading closest to that required to get to the GPS point.
  • I will use a PID loop on the steering servo and a compass mounted on the car (that isn't sweeping back and forth) to ensure that the car is turning towards the chosen heading.

Is there a better way to do this? (I considered going the camera route, but this seemed like an easier place to start)