Notifications
Clear all

Remote Control of Three Servos  

  RSS

Pugwash
(@pugwash)
Noble Member
Joined: 1 year ago
Posts: 1007
2019-11-12 2:23 pm  

Requirements:

  • 2 Arduino Unos or Nanos
  • 2 NRF24L04 Modules
  • 3 Pots
  • 3 Servos

The setup for one Servo can be found at:

https://howtomechatronics.com/tutorials/arduino/how-to-build-an-arduino-wireless-network-with-multiple-nrf24l01-modules/

To expand the number of controllable servos to three, two more pots should be connected to analogue pins A1 & A2, and two more Servos to digital pins D5 & D6.

The following code should be on the transmitting Arduino

/*
Arduino Wireless Network - Multiple NRF24L01 Tutorial
== Example 01 - Servo Control / Node 00 - Potentiometer ==
by Dejan, www.HowToMechatronics.com
Adapted for multiple Servos by Pugwash 2019.
Libraries:
nRF24/RF24,   https://github.com/nRF24/RF24  
nRF24/RF24Network,   https://github.com/nRF24/RF24Network  
*/
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>

RF24 radio(8, 10); // nRF24L01 (CE,CSN)
RF24Network network(radio); // Include the radio in the network
const uint16_t this_node = 00; // Address of this node in Octal format ( 04,031, etc)
const uint16_t node01 = 01;

int lastPotValue0;
int lastPotValue1;
int lastPotValue2;

int newPotValue0;
int newPotValue1;
int newPotValue2;

int angleValue;

void setup() {
  
  SPI.begin();
  radio.begin();
  network.begin(90, this_node); //(channel, node address)

  //get the initial pot values
  lastPotValue0 = analogRead(A0);
  lastPotValue1 = analogRead(A1);
  lastPotValue2 = analogRead(A2);  
}

void loop() {
  
  network.update();
  
  // read the values on Analog Pins A0, A1, A2
  newPotValue0 = analogRead(A0);
  newPotValue1 = analogRead(A1);
  newPotValue2 = analogRead(A2);

  // only transmit if the values have changed
  if(newPotValue0 != lastPotValue0){
    angleValue = map(newPotValue0, 0, 1023, 0, 180); // Convert the value to 0-180
    sendMyData(angleValue);
    lastPotValue0 = newPotValue0;
  }
  
  if(newPotValue1 != lastPotValue1){
    angleValue = map(newPotValue1, 0, 1023, 0, 180); // Convert the value to 0-180
    angleValue = angleValue + 1000;
    sendMyData(angleValue);
    lastPotValue1 = newPotValue1;
  }

  if(newPotValue2 != lastPotValue2){
    angleValue = map(newPotValue2, 0, 1023, 0, 180); // Convert the value to 0-180
    angleValue = angleValue + 2000;
    sendMyData(angleValue);
    lastPotValue2 = newPotValue2;
  }
}

void sendMyData(int angleValue1){
  RF24NetworkHeader header(node01); // (Address where the data is going)
  bool ok = network.write(header, &angleValue1, sizeof(angleValue1)); // Send the data
    
  }

And the following code on the Arduino controlling the Servos.

/*
Arduino Wireless Network - Multiple NRF24L01 Tutorial
== Example 01 - Servo Control / Node 01 - Servo motor ==
Adapted for multiple Servos by Pugwash 2019.
*/
#include <RF24.h>
#include <RF24Network.h>
#include <SPI.h>
#include <Servo.h>

RF24 radio(8, 10); // nRF24L01 (CE,CSN)
RF24Network network(radio); // Include the radio in the network
const uint16_t this_node = 01; // Address of our node in Octal format ( 04,031, etc)

// create six servo objects
Servo myservo0; 
Servo myservo1; 
Servo myservo2; 

void setup() {
  
  Serial.begin(9600);
  SPI.begin();
  radio.begin();
  network.begin(90, this_node); //(channel, node address)
  
  myservo0.attach(3);
  myservo1.attach(5);
  myservo2.attach(6);
  
}

void loop() {
  network.update();
  while ( network.available() ) { // Is there any incoming data?
    RF24NetworkHeader header;
    int incomingData;
    network.read(header, &incomingData, sizeof(incomingData)); // Read the incoming data
    Serial.println(incomingData);
    if(incomingData < 181){
      myservo0.write(incomingData);
    }
    if(incomingData >= 1000 && incomingData < 1181){
      myservo1.write(incomingData - 1000);
    }
    if(incomingData >= 2000 && incomingData < 2181){
      myservo2.write(incomingData - 2000);
      }  
  }
}

The Uno and Nano are limited to three servos because only 3 PWM pins are available, but this code can be easily adapted to more Servos if you use an Arduino Mega instead!

Have fun adapting this code! ? ? ? 


ZeFerby liked
Quote
Topic Tags
Pugwash
(@pugwash)
Noble Member
Joined: 1 year ago
Posts: 1007
2019-11-13 4:03 pm  

@robo-pi

I don't know whether you remember but a couple of months ago we were discussing the merits of 433MHz modules. Have you tried these NRF24L04 modules?

I have had a few of them lying around for a couple of months and today I finally got around to setting up a small test with two of them. The reception far surpasses the 433 modules, with a reliable signal through 4 concrete walls. something I wasn't getting with the 433s.

The setup was made without the small stubby antenna, and I am suitably impressed. The only drawback that I have found is that the modules must be suitably orientated where signal attenuation is present.


ReplyQuote
Pugwash
(@pugwash)
Noble Member
Joined: 1 year ago
Posts: 1007
2019-11-26 11:32 am  

@frogandtoad

It is time you got yourself an avatar. There must be a picture somewhere on the internet showing a pub sign "Frog and Toad", or something from "Wind in the Willows".

Early this morning, over my first cup o' tea, I was thinking about rewriting the code above, with my new-found knowledge of the struct objects. But firstly, I must correct the false statement above about only 3 PWM pins, I had meant to say "available", as this is how somebody else had wired up their own setup.

Now I am talking about six pots and six servos, one local Uno and one remote Uno/Nano.

The following is only my initial concept:

// servo0 connected to PWM pin D3
// servo1 connected to PWM pin D5
// servo2 connected to PWM pin D6
// servo3 connected to PWM pin D9
// servo4 connected to PWM pin D10
// servo5 connected to PWM pin D11
// pots connected to analog pins A0 to A5

typedef struct ServoData{
  byte servo0;
  byte servo1;
  byte servo2;
  byte servo3;
  byte servo4;
  byte servo5;
  byte checksum;  
  };

ServoData myObject; // declare the message object

byte tempArray[6];

void setup(){

  // get initial checksum
  tempArray[0] = AnalogRead(A0);
  tempArray[1] = AnalogRead(A1);
  tempArray[2] = AnalogRead(A2);
  tempArray[3] = AnalogRead(A3);
  tempArray[4] = AnalogRead(A4);
  tempArray[5] = AnalogRead(A5);
  
  lastChecksum = checkSum();

}

void loop(){

  tempArray[0] = AnalogRead(A0);
  tempArray[1] = AnalogRead(A1);
  tempArray[2] = AnalogRead(A2);
  tempArray[3] = AnalogRead(A3);
  tempArray[4] = AnalogRead(A4);
  tempArray[5] = AnalogRead(A5);
  
  newChecksum = checkSum(); 
  
  if(newChecksum != lastChecksum){
    
    myObject.servo0 = tempArray[0];
    myObject.servo1 = tempArray[1];
    myObject.servo2 = tempArray[2];
    myObject.servo3 = tempArray[3];
    myObject.servo4 = tempArray[4];
    myObject.servo5 = tempArray[5];
    myObject.checksum = newChecksum;
    
    radio.write(&myObject, sizeof(myObject));
    
    lastChecksum = newChecksum; 
  } 
}

byte checkSum(){
  
  byte result = tempArray[0];
  
  for (int i = 1; i < sizeof(tempArray); i++){
    result ^= tempArray[i];
  }  
  return result;  
}

This code is of course nowhere near finished!!

On the remote side, the checksum will be verified and if OK, the values passed to the servos. If not remote will set a flag and remote will send a request back to local to have the data resent until the flag is cleared. Only then will the values passed to the servos. The checksum routine is far more critical for controlling servos than reading display values from the BME280. Imagine what would happen if the remote was in a model aeroplane and it was getting corrupt data.

I was wondering what you thought about the basic concept?


ReplyQuote
frogandtoad
(@frogandtoad)
Honorable Member
Joined: 1 year ago
Posts: 540
2019-11-26 11:58 am  

@pugwash

Haha... I'll look into getting an Avatar... may even make my own in Blender 3D 🙂

Yes, as a concept, I like the idea of checksum (and of course, a lot of code I have posted has no real error checking at all, as it's mostly to show the basics), and would certainly implement important checks in production code.

I have to run (just started a new job and need some shut eye), but I'll have a closer look tomorrow.

BTW... the code I posted with the 2 pots/servos can be increased by the array size to allow for 16 pots, which will take it to the 32 byte limit.

Cheers!


ReplyQuote