Pages: [1] 2   Go Down
Author Topic: Controlling two servos over nRF24l01+  (Read 2355 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everyone,

I'm new to programming and microprocessing, however trying to understand and pushing hard.

Can anyone help to improve the following scetches so I can use 2 potentiometers to control 2 servos?

I have success doing only one at the moment!

Code for transmitter:

Code:
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <Servo.h>
 

Servo myservo;  // create servo object to control a servo
int rate;
int val;    // variable to read the value from the analog pin

void setup(){
 
  Serial.begin(9600);
  myservo.attach(3);
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(rate);
  Mirf.config();
}
 
void loop(){
 
  while(!Mirf.dataReady()){
  }
  Mirf.getData((byte *) &rate);
  val = rate;            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write(val);
  Serial.print("Position Received..");  // sets the servo position according to the scaled value
  Serial.println(val);
  delay(10);
}

Code for receiver:

Code:
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
 
int rate;
 
void setup(){
 
  Serial.begin(9600);
 
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(rate);
  Mirf.config();
}
 
void loop(){
  rate = analogRead(A0);
 
  Mirf.setTADDR((byte *)"serv1");
 
  Mirf.send((byte *) &rate);
 
  while(Mirf.isSending()){
  }
}
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think you have your code switched. Why send an int and then map to a byte? Map first, then send the byte sized value.

The payload size can be the size of two bytes (or two ints), rather than one. The payload can be an array, instead of a scalar.

What have you tried?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Maybe, I'm not that good in programming, could you make necessary modification and post back, then I could upload and relpy if that will work or not? Potensiometers hooked to Analog input 0 and 1, servos to Digital 4 and 5 respectively
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Move this:
Code:
  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)
to the sender.

On the sender, create an array of bytes:
Code:
byte vals[2];

Read analog pin 0, map the value, and store the result in vals[0].
Read analog pin 1, map the value, and store the result in vals[1].

Change this:
Code:
  Mirf.payload = sizeof(rate);
to
Code:
  Mirf.payload = sizeof(vals);

Change this:
Code:
  Mirf.send((byte *) &rate);
to
Code:
  Mirf.send(vals);

You should, then, be able to see how to change the receiver code to receive two bytes, and send them to the appropriate servos.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well I did some changes, however it does not work, can someone have a look and say what is wrong?

Code:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
 
int vals;

 
void setup(){
 
  Serial.begin(9600);
 
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setTADDR((byte *)"clie1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
  byte vals[2];
  vals[0] = analogRead(A0);
  vals = map(vals, 0, 1023, 0, 179);
 Serial.println(vals[0]);
  vals[1] = analogRead(A1);
  vals = map(vals, 0, 1023, 0, 179);
 Serial.println(vals[1]);
  Mirf.setTADDR((byte *)"serv1");
  Mirf.send((byte *) &vals);
 
  while(Mirf.isSending()){
  }
}
it says "invalid conversion from byte to long int"

when I remove this line " vals = map(vals, 0, 1023, 0, 179);"

and code for receiver:
Code:
// http://www.bajdi.com
// Nrf24L01 connected to Arduino Uno
// Nrf24L01 connection details http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo
// Receives analog value from transmitter and display it on serial monitor
 
 
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <Servo.h>
 

Servo myservo1;
Servo myservo2; // create servo object to control a servo
int vals;    // variable to read the value from the analog pin
int val1;
int val2;

void setup(){
 
  Serial.begin(9600);
  myservo1.attach(3);
  myservo2.attach(4);
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
 
  while(!Mirf.dataReady()){
  }
  Mirf.getData((byte *) &vals);    // reads the value of the potentiometer (value between 0 and 1023)
 
  byte vals[2];
val1 = vals[0];
val2 = vals[1]; // scale it to use it with the servo (value between 0 and 180)
  myservo1.write(val1);
  myservo2.write(val2);
    Serial.print("Position Received..");  // sets the servo position according to the scaled value
  Serial.println(val1);
  Serial.println(val2);
  delay(10);
}
it's compilling and after upload still nothing works!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here are changes I've done, now again one channel working Ok, other does not transmit or receiver does not receive it, don't know:

Transmitter:
Code:
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
 
int vals;

 
void setup(){
 
  Serial.begin(9600);
 
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
  int vals[2];
  vals[0] = analogRead(A0);
 Serial.println(vals[1]);
  vals[1] = analogRead(A1);
 Serial.println(vals[0]);
  Mirf.setTADDR((byte *)"serv1");
  Mirf.send((byte *) &vals);
  while(Mirf.isSending()){
  }
  delay(10);
}

receiver:

Code:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <Servo.h>
 

Servo myservo1;
Servo myservo2;
int vals;     
int val1;
int val2;

void setup(){
 
  Serial.begin(9600);
  myservo1.attach(3);
  myservo2.attach(4);
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
 
  while(!Mirf.dataReady()){
  }
  int vals[2];
  Mirf.getData((byte *) &vals);   
  val1 = vals[1];
  val1 = map(val1, 0, 1023, 0, 179);
  val2 = vals[0];
  val2 = map(val2, 0, 1023, 0, 179);
  myservo1.write(val1);
  myservo2.write(val2);
    Serial.println("Position Received..");   
  Serial.println(val1);
  Serial.println(val2);
  delay(10);
}
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
On the sender, create an array of bytes:
So, you created an array of ints. Why?

You created that array as a local variable with the same name as a global (scalar) variable. Why?

The mapping of int to val is not happening on the sender. Why not?

Your sender is sending two bytes, not four.

Your receiver also has global and local variables of the same name. This is really NOT a good idea. So, stop it. NOW.

If you are going to ask for advice, and then ignore it, I'm going to stop offering it.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi PaulS

Sorry I'm new to programming and trying my best to understand what is what and how.

the reason I changed byte o int is that when I put int type sender only sends data within range 0-255 and I need data to be transmitted in the range of 0-1023 to make sure Servo motors are working in the range

Could you please change the code and post it back, then I might understand better

Thanks
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I need data to be transmitted in the range of 0-1023 to make sure Servo motors are working in the range
No, you don't. The call to map converts the value in the range 0 to 1023 into an angle in the range 0 to 179.

Now, even without taking my shoes off, I can see that 179 is less than 255. So, the question is why not do the mapping on the sender end, and simply send the angle. As a byte.

Until you answer this question, we can make no progress.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, thanks for that, looks like now I start thinking :-)

Looks like transmitter side is ready:

Code:
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
 
byte vals [2];
int val1;
int val2;
 
void setup(){
 
  Serial.begin(9600);
 
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
  val1 = analogRead(A1);
  val1 = map(val1, 0, 1023, 0, 179);
  vals[0] = val1;
  Serial.println(vals[0]);
 
  val2 = analogRead(A2);
  val2 = map(val2, 0, 1023, 0, 179);
  vals[1] = val2;
  Serial.println(vals[1]);
 
  Mirf.setTADDR((byte *)"serv1");
  Mirf.send((byte *) &vals);
  while(Mirf.isSending()){
  }
  delay(100);
}

Now I'm going to make changes to the receiver, let's see if that will work!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are F-n Genius:

Finally, code for receiver:
Code:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <Servo.h>
 

Servo myservo1;
Servo myservo2;
byte vals[2];



void setup(){
 
  Serial.begin(9600);
  myservo1.attach(3);
  myservo2.attach(4);
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"serv1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
}
 
void loop(){
 
  while(!Mirf.dataReady()){
  }
 
  Mirf.getData((byte *) &vals);   

  Serial.print("H Position Received..");
  Serial.println(vals[0]);
  myservo1.write(vals[0]);
  Serial.print("V Position Received..");   
  Serial.println(vals[1]);
  myservo2.write(vals[1]);
  Serial.print("Vals[0]:");
  Serial.println(vals[0]);
  Serial.print("Vals[1]:");
  Serial.println(vals[1]);
  delay(10);
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I need data to be transmitted in the range of 0-1023 to make sure Servo motors are working in the range
No, you don't. The call to map converts the value in the range 0 to 1023 into an angle in the range 0 to 179.

Now, even without taking my shoes off, I can see that 179 is less than 255. So, the question is why not do the mapping on the sender end, and simply send the angle. As a byte.

Until you answer this question, we can make no progress.

Question:

Why I could not use Int or long for this?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Question:

Why I could not use Int or long for this?
You could, if you size the payload correctly and setup the array correctly.

The issue is that on the receiver, you get an array of bytes, so reconstructing the int or long values is more difficult. Not hard, and certainly not impossible, but more complicated than you need.

If you want to deal with ints, highByte(), lowByte() and word() bear looking into. For longs, unions are the way to go.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

PaulS thanks for help, appreciated!

I hooked up LCD Display to this set-up, currently working on the menu.

I hope in a year or so, I'll get professional programmer for robottech, currently - this is my objective, there is nothing interesting rather than this for me!

Again Appreciate your help, was really usefull!
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 25
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So few more steps behind!

I got NRF24L01+ modules to communicate to each other, send receive required arrays of data, to control servos and few more bits and pieces.

Project I'm working at the moment is to control ROV and receive data from it's sensors.

I also attached LCD screen to the receiver and make it to display battery bar, I had to spend a day or so to figure out why Arduino cant show fluctuations in power supply and found that source of power actualy was feeding the resistor divider, there for relative change in voltage were sending the same resut back to the analog read pin, did a lot of research and finally found the issue. It was not that easy, because the prototyping board was so overloaded with wires, could not figure out at the end what is connected wrong!
As they say : "If it does not look good, probably it's not good ))))"

Now I need a help from forum and Arduino experts to suggest the way to fix Radio Signal indicator bar, at the moment it's just picture, but I need to get it working, principle might be the following: Transmitter sends signal, then listens to the reply from the receiver, if receiver reply received within certain time frame, then it's reflected on the signal bar, if time is long, signal bar is small, which means packet rather were not received or it took several commands to be sent before receiver finally received and replied. Not sure if I'm on the right path, as I'm not subject expert and this is my first project, but quite abitious!

Here is the code of the transmitter, which needs to be completed:
Code:
#include "U8glib.h"
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include "LowPower.h"

U8GLIB_ST7920_128X64 u8g(6, 5, 4, U8G_PIN_NONE); 

byte vals [10];
byte sens [10];

int val1;
int val2;
int PosX;
int PosY;
int lcdbl = 9;

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

void draw(void) {
  // graphic commands to redraw the complete screen should be placed here 
  u8g.setFont(u8g_font_unifont);
  u8g.setFont(u8g_font_u8glib_4);
}

// Arduino master setup
void setup(void) {
 

  if ( u8g.getMode() == U8G_MODE_R3G3B2 )
    u8g.setColorIndex(255);     // white
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
    u8g.setColorIndex(3);         // max intensity
  else if ( u8g.getMode() == U8G_MODE_BW )
    u8g.setColorIndex(1);         // pixel on
   
  Mirf.spi = &MirfHardwareSpi;
  Mirf.init();
  Mirf.setRADDR((byte *)"clie1");
  Mirf.payload = sizeof(vals);
  Mirf.config();
 
  pinMode(lcdbl, OUTPUT);
}

void loop(void) {
  //Serial.begin(9600);
  digitalWrite(lcdbl, HIGH);
 
  val1 = analogRead(A1);
  val1 = map(val1, 0, 1023, 0, 179);
  vals[0] = val1;
  //Serial.println(val1);
  val2 = analogRead(A2);
  val2 = map(val2, 0, 1023, 0, 179);
  vals[1] = val2;
  //Serial.println(val2);
 
  Mirf.setTADDR((byte *)"serv1");
  Mirf.send((byte *) &vals);
  while(Mirf.isSending()){
  }
 
  while(!Mirf.dataReady()){
    //Serial.println("Waiting for Respond:");
    if ( millis() > 1000 ) {
      //Serial.println("Timeout on response from server!");
      return;
    }
  }
 
  Mirf.getData((byte *) &sens);
 
  u8g.firstPage(); 
  do {
draw();
   
    u8g.drawStr( 30, 4, "LCD Joystick_V1.0");
    u8g.drawStr( 24, 12, "JoyStick Pos");
    u8g.drawStr( 90, 12, "Spider");
   
    u8g.drawLine(3, 0, 3, 4);    //Anntena
    u8g.drawLine(2, 2, 0, 0);
    u8g.drawLine(4, 2, 6, 0);
   
    u8g.drawBox(7, 4, 2, 1);      // Signal Bar
    u8g.drawBox(10, 3, 2, 2);
    u8g.drawBox(13, 2, 2, 3);
    u8g.drawBox(16, 1, 2, 4);
    u8g.drawBox(19, 0, 2, 5);
   
    u8g.drawFrame(13, 6, 115, 58);   //Menu Frame
    u8g.drawLine(76, 6, 76, 63);
   
    u8g.drawStr( 69, 42, "x");
    u8g.drawLine (15, 35, 74, 35);   // X axel
    u8g.drawLine (16, 36, 18, 37);
    u8g.drawLine (16, 34, 18, 33);
    u8g.drawLine (73, 36, 71, 37);
    u8g.drawLine (73, 34, 71, 33);   
   
    u8g.drawStr( 49, 18, "y");
    u8g.drawLine (45, 13, 45, 61);   //Y axel
    u8g.drawLine (46, 14, 47, 16);
    u8g.drawLine (44, 14, 43, 16);
    u8g.drawLine (46, 60, 47, 58);
    u8g.drawLine (44, 60, 43, 58);   
 
   
  //Serial.begin (9600);                    // Servo Position on coordinates
  PosX = analogRead(A1);
  PosX = map(PosX, 0, 1023, 0, 35);
  //Serial.println(PosX);
  PosY = analogRead(A2);
  PosY = map(PosY, 0, 1023, 0, 35);
  //Serial.println(PosY);
  u8g.drawFrame(PosX+28, PosY+18, 3, 3);
 
  u8g.setPrintPos(80,23);
  u8g.print("H Servo:");
  u8g.setPrintPos(113,23);
  u8g.print(sens[0]);
  u8g.setPrintPos(80,28);
  u8g.print("V Servo:");
  u8g.setPrintPos(113,28);
  u8g.print(sens[1]);
 
  u8g.setPrintPos(80,33);
  u8g.print("Hum(%): ");
  u8g.setPrintPos(113,33);
  u8g.print((float)sens[2]);
  u8g.setPrintPos(80,38);
  u8g.print("Temp C*: ");
  u8g.setPrintPos(113,38);
  u8g.print(sens[3]);
 
  u8g.setPrintPos(80,43);
  u8g.print("Voltage: ");
  u8g.setPrintPos(113,43);
  float voltage = analogRead(A4);    //voltmeter
  //Serial.begin(9600);
  voltage = map(voltage,0,1023,0,1008);
  //Serial.println(voltage);
  u8g.print(voltage/100);
  u8g.setPrintPos(113,48);                   //Arduino Voltage
  u8g.print( (float) readVcc()/1000);
 
  int battery = voltage;
  u8g.drawLine(100, 0, 125, 0);    // Battery Bar
  u8g.drawLine(100, 5, 125, 5);
  u8g.drawLine(100, 0, 100, 5);
  u8g.drawLine(125, 0, 125, 1);
  u8g.drawLine(125, 1, 127, 1);
  u8g.drawLine(127, 1, 127, 4);
  u8g.drawLine(127, 4, 125, 4);
  u8g.drawLine(125, 4, 125, 5);
 
  battery = map( battery, 620, 820, 0, 27);
  u8g.drawBox(101, 1, battery, 4);
 
  if( voltage <=610)
  {
     u8g.drawFrame(0, 0, 128, 64);
     u8g.setColorIndex(3);
     u8g.setPrintPos(37,35);
     u8g.print("LOW BATTERY !!!");
     delay(2000);
     digitalWrite(lcdbl, LOW);
     delay(2000);
    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
   
  }

//Serial.begin(9600);
//Serial.println("Start Receiving Data from Spider:");

//Serial.println(sens[2]);
//Serial.println(sens[3]);
//Serial.println(sens[4]);
//Serial.println(sens[5]);
//Serial.println(sens[6]);
//Serial.println(sens[7]);

  } while( u8g.nextPage() );
 
  // rebuild the picture after some delay
  delay(10);
 
 
    }












and here is the picture of the setup!
And this is the beast to be controlled:


* IMAG1653.jpg (1547.6 KB, 3264x1840 - viewed 75 times.)
Logged

Pages: [1] 2   Go Up
Jump to: