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.
I have a question about the lcd. Im trying to read serial inputs and display them, but it seems that the cursor is jumping all around and overwriting or randomly plotting the info…can you please email me?
Hello
Do you have any examples of how to connect:
nRF24L01 and BH1750FVI =>(arduino pro mini TX)
nRF24L01 => (duemilanove RX)
Have a look at this to connect the nRF24L01 modules: http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
A pro mini and a Duemilanove use the same pins. The BH1750FVI is an I2C sensor, so it connects to A4 (SDA) and A5 (SDL).
Hello, I have a nRF24L01 card and an Arduino UNO. I need to clone a remote control an electric curtain that uses RF 2.4GHZ, it is possible that this procedure and control electric curtain with Arduino UNO and module nRF24L01?
Rodrigo, nRF24L01 modules will only work with other nRF24L01 modules. The 2.4GHz is just the bandwidth that they work at. Lots of devices use that bandwidth (like wifi) but that doesn’t mean that they can communicate with each other. They all use their own “protocol”.
Im having this error “In function ‘void loop()’: error: void value not ignored as it ought to be” at line “done = radio.read( joystick, sizeof(joystick) );”.
Have you changed something on your library (nRF24L01.h or RF24.h)? im using Arduino 1.6.3 and cant get this working without changing it.
I am also receiving the same error. Did you find the solution?