Dagu Rover 5 remote control with nRF24L01 from Bajdi on Vimeo.
I have updated my sketch to remote control the Rover 5. There were a couple of things I wanted to try out. The Dagu 4 channel motor controller I use is equipped with 4 current outputs. These outputs give a 0 to 5V signal, 5V equals 5A. I hooked up all 4 sensor outputs to 4 analog inputs on the Red back spider. To know how much amps a motor draws the analogread value is divided by 1023 and then multiplied by 5. Another thing I wanted to try was sending back data from the Rover to my remote using the RF24 Arduino library. This is very handy when you’re testing new code. Attaching a USB cable to your Rover while it’s driving around is not very practical. This gave me some trouble, when I originally wrote the sketch I had a lot of serial.print lines in the code and my sketch worked. When I removed these serial.print statements the sketch stopped working. Very strange and it took me a long time to figure out. When I replaced the serial.print statements with a tiny delay the code worked. To make this delay I did not use the delay function, but used the code from the “blink without delay” example sketch. You don’t want to have delay statements in code for a remote controlled vehicle, I tried it and it made my Rover very unresponsive. After getting this to work I attached an I2C LCD to my “remote” so I could print the motor current values to it. I only have had an 2×16 lcd and after printing the 4 values to the lcd there is no more space for other stuff. I’ve just received a 4×20 I2C LCD, cost me 20$ on Ebay. This gives me some more “room” to play with. As you can see in the video my Rover 5 has become a big cable mess, should do something about that
Here is the sketch that I’m using for the remote;
// http://www.bajdi.com
// Nrf24L01 connected to Arduino Uno
// Nrf24L01 connection details http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// Transmit analog values from joystick to the receiver using RF24 library
// Receive 4 floats (current from the motors) from Rover 5 motor controller
#include <SPI.h>
#include <nRF24L01.h>
#include "RF24.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bounce.h>
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27
RF24 radio(8,7);
const uint64_t pipes[2] = {
0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
int joystick[3];
float current[4];
const int z = 2;
int roverState = LOW; // the current state of the output pin
Bounce bouncer = Bounce( z, 5 );
long previousMillis = 0;
long interval = 25;
void setup(){
pinMode(z, INPUT);
radio.begin();
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("M1=");
lcd.setCursor(8,0);
lcd.print("M2=");
lcd.setCursor(0,1);
lcd.print("M3=");
lcd.setCursor(8,1);
lcd.print("M4=");
}
void loop(){
joystick[0] = analogRead(A0);
joystick[1] = analogRead(A1);
joystick[2] = roverState;
if ( bouncer.update() ) {
if ( bouncer.read() == HIGH) {
if ( roverState == LOW ) {
roverState = HIGH;
}
else {
roverState = LOW;
}
}
}
if ( radio.available() )
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
// Dump the payloads until we've gotten everything
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( ¤t, sizeof(current) );
}
}
lcd.setCursor(3,0);
lcd.print(current[0]);
lcd.setCursor(11,0);
lcd.print(current[1]);
lcd.setCursor(3,1);
lcd.print(current[2]);
lcd.setCursor(11,1);
lcd.print(current[3]);
radio.stopListening();
bool ok = radio.write( &joystick, sizeof(joystick) );
radio.startListening();
}
}
This is the sketch that goes in the Red back spider that controls the Rover 5:
// http://www.bajdi.com
// Dagu Rover 5 chassis with 4 motors
// Remote control through Nrf24L01 2,4GHz wireless module
// µcontroller = Dagu Red back spider, Arduino Mega 1280 compatible
// Motor controller = Dagu 4 channel motor controller
// Motor 1 and 2 on the left
// Motor 3 and 4 on the right
// Sent 4 floats (motor current) to transmitter (remote)
#include <SPI.h>
#include <nRF24L01.h>
#include "RF24.h"
#include "Ultrasonic.h"
#include <VarSpeedServo.h>
/* Nrf24L01 pinout
1 GND
2 VCC (3,3V)
3 CE pin 48 on Mega 1280
4 CSN pin 49 on Mega 1280
5 SCK pin 52 on Mega 1280
6 MOSI pin 51 on Mega 1280
7 MISO pin 50 on Mega 1280
8 IRQ (not used)
*/
RF24 radio(48,49);
const uint64_t pipes[2] = {
0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
int DirM1 = 30; // direction motor 1
int DirM2 = 31; // direction motor 2
int DirM3 = 32; // direction motor 3
int DirM4 = 33; // direction motor 4
int PWMM1 = 4; // pwm motor 1
int PWMM2 = 5; // pwm motor 2
int PWMM3 = 6; // pwm motor 3
int PWMM4 = 7; // pwm motor 4
int fs; // forward speed
int bs; // backward speed
int ls; // turn left speed
int rs; // turn right speed
int bat; // analog reading of battery voltage through voltage divider
const int lowbat = 34; // low battery led (red)
const int buzzer = 35; // buzzer
const int orange = 38; // orange leds
const int headlight = 39; // white leds
const int TRIG = 36;
const int ECHO = 37;
Ultrasonic SRF6A(TRIG, ECHO);
VarSpeedServo SRF6AServo; // servo objects
int servoSpeeds = 30; // sweep speed, 1 is slowest, 255 fastest)
int servoMinPosition = 20; // the minumum servo angle
int servoMaxPosition = 110; // the maximum servo angle
int joystick[3]; // Array with 2 analog values (X,Y-axis) and one digital (Z-axis) from transmitter/joystick
float current[4]; // Array with the 4 motor current values, to sent to remote control
int apin[] = {
A1, A2, A3, A4 }; // analog pin array
long previousMillis = 0;
long interval = 25;
void setup() {
pinMode(DirM1, OUTPUT); // direction motor 1, left front
pinMode(DirM2, OUTPUT); // direction motor 2, left rear
pinMode(DirM3, OUTPUT); // direction motor 3, right front
pinMode(DirM4, OUTPUT); // direction motor 4, right rear
pinMode(PWMM1, OUTPUT); // PWM motor 1
pinMode(PWMM2, OUTPUT); // PWM motor 2
pinMode(PWMM3, OUTPUT); // PWM motor 3
pinMode(PWMM4, OUTPUT); // PWM motor 4
pinMode(lowbat, OUTPUT); // low battery led (red)
pinMode(buzzer, OUTPUT); // buzzer
pinMode(orange, OUTPUT); // orange leds
pinMode(headlight, OUTPUT); // white leds
SRF6AServo.attach(8);
SRF6AServo.slowmove(servoMinPosition,servoSpeeds) ; // start sweeping from min position
radio.begin();
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
}
void loop() {
bat = analogRead(A0);
if (bat < 760) // 760 / 1023 * 5 * 2 = 7,4V from battery
{
digitalWrite(lowbat, HIGH);
}
else
{
digitalWrite(lowbat, LOW);
}
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
bool done = false;
while (!done)
{
// Fetch the payload, and see if this was the last one.
done = radio.read( &joystick, sizeof(joystick) );
}
if (bat > 760 && joystick[2] == HIGH) // 760 / 1023 * 5 * 2 = 7,4V from battery
{
digitalWrite(headlight, HIGH); // turn on headlights
if( SRF6AServo.read() == servoMinPosition)
{
SRF6AServo.slowmove(servoMaxPosition,servoSpeeds) ;
}
else if( SRF6AServo.read() == servoMaxPosition)
{
SRF6AServo.slowmove(servoMinPosition,servoSpeeds) ;
}
if(SRF6A.Ranging(CM) < 5){
digitalWrite(buzzer, HIGH); // we're going to crash
}
else {
digitalWrite(buzzer, LOW);
}
if (joystick[0] > 500 && joystick[0] < 540 && joystick[1] > 490 && joystick[1] < 530 ) // joystick is centered
{
stopped();
}
if (joystick[0] <= 500 && joystick[1] > 490 && joystick[1] < 530) // joystick forward = all motors forward
{
fs = (map(joystick[0], 500, 0, 35, 255));
forward(fs);
}
if (joystick[0] >= 540 && joystick[1] > 490 && joystick[1] < 530) // joystick backward = all motors backward
{
bs = (map(joystick[0], 540, 1023, 35, 255));
backward(bs);
}
if (joystick[1] <= 490 && joystick[0] > 500 && joystick[0] < 540) // joystick left = left motors backward && right motors forward
{
ls = (map(joystick[1], 490, 0, 35, 255));
turnleft(ls);
}
if (joystick[1] >= 530 && joystick[0] > 500 && joystick[0] < 540) // joystick right = left motors forward && right motors backward
{
rs = (map(joystick[1], 530, 1023, 35, 255));
turnright(rs);
}
}
else {
stopped();
digitalWrite(headlight, LOW); // turn off headlights
}
}
// 4 analog readings from motor controller = motor current
for (int i=0; i<4; i++)
{
current[i] = analogRead( apin[i] )/ 1023.0 * 5.0;
}
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
radio.stopListening();
bool ok = radio.write( ¤t, sizeof(current) );
radio.startListening();
}
}
void stopped()
{
analogWrite(PWMM1, 0);
analogWrite(PWMM2, 0);
analogWrite(PWMM3, 0);
analogWrite(PWMM4, 0);
digitalWrite(orange, LOW);
}
void forward(int fs)
{
digitalWrite(DirM1, HIGH);
digitalWrite(DirM2, HIGH);
digitalWrite(DirM3, HIGH);
digitalWrite(DirM4, HIGH);
analogWrite(PWMM1, fs);
analogWrite(PWMM2, fs);
analogWrite(PWMM3, fs);
analogWrite(PWMM4, fs);
digitalWrite(orange, LOW);
}
void backward(int bs)
{
digitalWrite(DirM1, LOW);
digitalWrite(DirM2, LOW);
digitalWrite(DirM3, LOW);
digitalWrite(DirM4, LOW);
analogWrite(PWMM1, bs);
analogWrite(PWMM2, bs);
analogWrite(PWMM3, bs);
analogWrite(PWMM4, bs);
digitalWrite(orange, LOW);
}
void turnleft(int ls)
{
digitalWrite(DirM1, LOW);
digitalWrite(DirM2, LOW);
digitalWrite(DirM3, HIGH);
digitalWrite(DirM4, HIGH);
analogWrite(PWMM1, ls);
analogWrite(PWMM2, ls);
analogWrite(PWMM3, ls);
analogWrite(PWMM4, ls);
digitalWrite(orange, HIGH);
}
void turnright(int rs)
{
digitalWrite(DirM1, HIGH);
digitalWrite(DirM2, HIGH);
digitalWrite(DirM3, LOW);
digitalWrite(DirM4, LOW);
analogWrite(PWMM1, rs);
analogWrite(PWMM2, rs);
analogWrite(PWMM3, rs);
analogWrite(PWMM4, rs);
digitalWrite(orange, HIGH);
}
These sketches are becoming rather big, the transmitter sketch is more then 9000 bytes and the Rover 5 sketch is over 11000 bytes. The Dagu red back spider controller is based on the ATmega 1280 and has 128kb (minus the bootloader) of memory, I don’t think I will ever have to worry about running out of space 
The transmitter or remote I currently use is an Arduino Duemilanove with a sensor shield on top of it. There is a nRF24L01 module, small joystick and I2C LCD display connected to it. You can find a picture of it here. The only thing that holds it all together are the wires connecting everything. So I’ve decided to make an enclosure for all these parts, I will have some plexiglass cut up to fit it all. I’ve ordered a joystick shield with some more buttons on it (always handy). And I’ve already received a 2×20 I2C LCD display, I will use a small 2 cell 500mAh Lipo battery to power it all. I bought 2 small 2 cell 500mAh Lipo batteries for 12,5€ on Ebay. I prefer them to AA batteries.