Joystick Robot Control


Wireless Joystick for Arduino Robot Car with nRF24L01


Introduction

Arduinos are great for many reasons, one of them being their ability to wire up to almost anything.  But there are times when you want to connect to your Arduino without using any wires, and when you do get the desire to go wireless there are several methods to choose from.
 this article (and in the corresponding video) I will examine one method of Arduino wireless communications, the nRF24L01+ module.  This is an inexpensive module that provides 2-way communications using the 2.4 GHz band. This band is free to use for low power devices without a license and in some cases can be useful up to a kilometer (although you should expect much shorter ranges without a special antenna).

The nRF24L01+ is available in a number of different configurations, in this article I’ll look at a couple of the more popular ones. We’ll hook them up and use a very extensive library to facilitate communications between them.
The nRF24L01+ is available in a number of different configurations, in this article I’ll look at a couple of the more popular ones. We’ll hook them up and use a very extensive library to facilitate communications between them.

The nRF24L01+

The nRF24L01+ is the part number of a common chip used to construct 2.4 GHz transmitters and receivers, or “transceivers”. This chip has been used to create some simple and inexpensive modules that can be used to transmit and receive data using the 2.4 GHz band.
There are a variety of modules available based upon the nRF24L01, I’m going to use two very common ones in this article. If you have a different module it should work fine, just be sure to observe the wiring and especially the power supply requirements.
The two modules I’m using are quite similar and are interchangeable, the difference between them is that one of them has a built in Low Noise Amplifier (LNA) and an external antenna connection.  I tend to prefer that one even though it’s a bit more expensive as it can be used for reliable data communications over a pretty fair distance. Unless you live in a castle it will probably be more than sufficient to cover your entire house.
All of the experiments, including the wireless joystick, may be built with either module (they share the same pinouts) but you’ll achieve better range with the model with the external antenna.

  1. GND. This is the Ground Pin. It is usually marked by encasing the pin in a square so it can be used as a reference for identifying the other pins.
  2. VCC. The positive voltage. This can be anywhere from 1.9 to 3.9 volts. It os NOT 5-volt tolerant!
  3. CE. Chip Enable, an active-high pin. When selected the nRF24L01 will either transmit or receive, depending upon which mode it is currently in.
  4. CSN. Chip Select Not. Thi is an active-low pin, it is the pin that the SPI bus uses to select the nRF24L01 slave.
  5. SCK. The Clock pin, an external clock source provided by the SPI bus Master.
  6. MOSI. Master Out Slave In. The input to the nRF24L01.
  7. MISO. Master In Slave Out. The output from the nRF24L01.
  8. IRQ. The Interrupt output pin.
If you did build the original car there are some changes you will need to make, specifically in how the L298N H-Bridge motor controller is hooked up. The original design uses some of the pins required by the nRF24L01 so it needs to be required.
Here is the new Robot Car schematic:
The connections to the nRF24L01 module are exactly the same as they have been in our other experiments, no surprise there. You can use any type of nRF24L01 module but I strongly recommend using the model with the external antenna for improved performance, at least on the car side.

Joystick Transmitter Code


//Prateek #include #include // Include dependant SPI Library #include // Define Joystick Connections #define joyVert A0 #define joyHorz A1 // Define Joystick Values - Start at 512 (middle position) int joyposVert = 512; int joyposHorz = 512; // Define addresses for radio channels #define CLIENT_ADDRESS 1 #define SERVER_ADDRESS 2 // Create an instance of the radio driver RH_NRF24 RadioDriver; // Sets the radio driver to NRF24 and the client address to 1 RHReliableDatagram RadioManager(RadioDriver, CLIENT_ADDRESS); // Declare unsigned 8-bit motorcontrol array // 2 Bytes for motor speeds plus 1 byte for direction control uint8_t motorcontrol[3]; // Define the Message Buffer uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN]; void setup() { // Setup Serial Monitor Serial.begin(9600); // Initialize RadioManager with defaults - 2.402 GHz (channel 2), 2Mbps, 0dBm if (!RadioManager.init()) Serial.println("init failed"); // Set initial motor direction as forward motorcontrol[2] = 0; } void loop() { // Print to Serial Monitor Serial.println("Reading motorcontrol values "); // Read the Joystick X and Y positions joyposVert = analogRead(joyVert); joyposHorz = analogRead(joyHorz); // Determine if this is a forward or backward motion // Do this by reading the Verticle Value // Apply results to MotorSpeed and to Direction if (joyposVert < 460) { // This is Backward // Set Motors backward motorcontrol[2] = 1; //Determine Motor Speeds // As we are going backwards we need to reverse readings motorcontrol[0] = map(joyposVert, 460, 0, 0, 255); motorcontrol[1] = map(joyposVert, 460, 0, 0, 255); } else if (joyposVert > 564) { // This is Forward // Set Motors forward motorcontrol[2] = 0; //Determine Motor Speeds motorcontrol[0] = map(joyposVert, 564, 1023, 0, 255); motorcontrol[1] = map(joyposVert, 564, 1023, 0, 255); } else { // This is Stopped motorcontrol[0] = 0; motorcontrol[1] = 0; motorcontrol[2] = 0; } // Now do the steering // The Horizontal position will "weigh" the motor speed // Values for each motor if (joyposHorz < 460) { // Move Left // As we are going left we need to reverse readings // Map the number to a value of 255 maximum joyposHorz = map(joyposHorz, 460, 0, 0, 255); motorcontrol[0] = motorcontrol[0] - joyposHorz; motorcontrol[1] = motorcontrol[1] + joyposHorz; // Don't exceed range of 0-255 for motor speeds if (motorcontrol[0] < 0)motorcontrol[0] = 0; if (motorcontrol[1] > 255)motorcontrol[1] = 255; } else if (joyposHorz > 564) { // Move Right // Map the number to a value of 255 maximum joyposHorz = map(joyposHorz, 564, 1023, 0, 255); motorcontrol[0] = motorcontrol[0] + joyposHorz; motorcontrol[1] = motorcontrol[1] - joyposHorz; // Don't exceed range of 0-255 for motor speeds if (motorcontrol[0] > 255)motorcontrol[0] = 255; if (motorcontrol[1] < 0)motorcontrol[1] = 0; } // Adjust to prevent "buzzing" at very low speed if (motorcontrol[0] < 8)motorcontrol[0] = 0; if (motorcontrol[1] < 8)motorcontrol[1] = 0; //Display the Motor Control values in the serial monitor. Serial.print("Motor A: "); Serial.print(motorcontrol[0]); Serial.print(" - Motor B: "); Serial.print(motorcontrol[1]); Serial.print(" - Direction: "); Serial.println(motorcontrol[2]); //Send a message containing Motor Control data to manager_server if (RadioManager.sendtoWait(motorcontrol, sizeof(motorcontrol), SERVER_ADDRESS)) { // Now wait for a reply from the server uint8_t len = sizeof(buf); uint8_t from; if (RadioManager.recvfromAckTimeout(buf, &len, 2000, &from)) { Serial.print("got reply from : 0x"); Serial.print(from, HEX); Serial.print(": "); Serial.println((char*)buf); } else { Serial.println("No reply, is nrf24_reliable_datagram_server running?"); } } else Serial.println("sendtoWait failed"); delay(100); // Wait a bit before next transmission }

Joystick Receiver Code



// Prateek #include #include // Include dependant SPI Library #include // Define addresses for radio channels #define CLIENT_ADDRESS 1 #define SERVER_ADDRESS 2 // Motor A Connections int enA = 9; int in1 = 14; int in2 = 4; // Motor B Connections int enB = 5; int in3 = 7; int in4 = 6; // Create an instance of the radio driver RH_NRF24 RadioDriver; // Sets the radio driver to NRF24 and the server address to 2 RHReliableDatagram RadioManager(RadioDriver, SERVER_ADDRESS); // Define a message to return if values received uint8_t ReturnMessage[] = "JoyStick Data Received"; // Define the Message Buffer uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN]; void setup() { // Setup Serial Monitor Serial.begin(9600); // Set all the motor control pins to outputs pinMode(enA, OUTPUT); pinMode(enB, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); pinMode(in3, OUTPUT); pinMode(in4, OUTPUT); // Initialize RadioManager with defaults - 2.402 GHz (channel 2), 2Mbps, 0dBm if (!RadioManager.init()) Serial.println("init failed"); } void loop() { if (RadioManager.available()) { // Wait for a message addressed to us from the client uint8_t len = sizeof(buf); uint8_t from; if (RadioManager.recvfromAck(buf, &len, &from)) { //Serial Print the values of joystick //Serial.print("got request from : 0x"); //Serial.print(from, HEX); //Serial.print(": MotorA = "); //Serial.print(buf[0]); //Serial.print(" MotorB = "); //Serial.print(buf[1]); //Serial.print(" Dir = "); //Serial.println(buf[2]); // Set Motor Direction if (buf[2] == 1) { // Motors are backwards digitalWrite(in1, LOW); digitalWrite(in2, HIGH); digitalWrite(in3, LOW); digitalWrite(in4, HIGH); }else{ // Motors are forwards digitalWrite(in1, HIGH); digitalWrite(in2, LOW); digitalWrite(in3, HIGH); digitalWrite(in4, LOW); } // Drive Motors analogWrite(enA, buf[1]); analogWrite(enB, buf[0]); // Send a reply back to the originator client, check for error if (!RadioManager.sendtoWait(ReturnMessage, sizeof(ReturnMessage), from)) Serial.println("sendtoWait failed"); } } }

Conclusion

As you can see the nRF24L01 can be used to create some very useful wireless projects with very little code, thanks to the RadioHead library.  If building robot cars isn’t your thing you can still find a lot of use for this powerful combination, and I’ll be featuring some more projects using these devices very soon.
PHOTO


0 Comments