[SOLVED***] int values "transformed" over wireless data sent, why?

*** Solved here means the problem disappeared after applying some brute OCD copy/paste/merge code. Exact origin of it? Well I choose not to dwell on it.

 

Well, while developing my remote control/receiver node all was well when unidirectional communication... and then I decided to add bidirectionality in order to get back feedback/telemetric data.

I'm using RF24L01+ radio modules and the RF24 library to handle them.

The Remote Control sends a struct with X & Y integer values and an array of booleans corresponding to button pushes.

That works great, X values makes the test servo sweep on the receiver node, and the button pushes toggle LEDs. I've also read their values via serial connection and they are what they should be (that is, what is sent from the transmitter is what is got in the receiver.

I've now associated the buttons pushes in order to decrement/increment a variable (which it does fine as tested by serial reading). The variable ranges from 70 to 120 (in increments of 10). However, when I send it over with radio.write() the values I get on the remote control lcd... are somewhat different...

Send 70 .... get 17990. I've already been told that 70 == 0x46 and that 17990 == 0x4646 ... so there's a duplicating thinguie of sorts...

the problem is that I don't know why it happens... the TX --> RX works fine... can't see why RX --> TX is failing like this...

I only suspect it may have something to do with the second paramenter from the write() method...

http://maniacbug.github.com/RF24/classRF24.html#a4cd4c198a47704db20b6b5cf0731cd58

but I've tried a few options (half-blindly)... but no success...

If there's no fault there... I guess the other culprit would be the LCD library? but I have no idea why it would be transforming the 70 into 17990 ... but then again, what do I know? that's why I am asking...

Below follows the code, with dirty comment outs and everything so you can see some of the fiddlings I've been doing...

Remote control code:

// include the library code:
#include <LiquidCrystal.h>
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"

// analog pin reading V_out/V2 from voltage divider
const int battPin = A5;

// button ‘pad’ pin
const int buttonPin = A3;

// Button setup schematics

//         Analog pin 5
//            |
//Ground–1K–|--------|--------|-------|
//            |        |        |       |
//           btn1     btn2     btn3    btn4
//            |        |        |       |
//         220 Ohm  390 Ohm  680 Ohm   2.2K
//            |--------|--------|-------|-- +5V

int j = 1;
// ‘j’ is the integer used in scanning the array designating column number
// these ranges below are dependent on the schematics above and may 
// need to be adjusted manually to compensate for various factors
int Button[15][3] = {{1, 836, 840}, // button 1
                     {2, 732, 738}, // button 2
                     {3, 600, 625}, // button 3
                     {4, 310, 335}, // button 4
                     
                     {5, 890, 900}, // button 1 + 2
                     {6, 870, 880}, // button 1 + 3
                     {7, 840, 860}, // button 1 + 4
                     {8, 810, 830}, // button 2 + 3
                     {9, 760, 780}, // button 2 + 4
                     {10, 665, 685} // button 3 + 4
                     };

int label = 0; // for reporting the button label
int counter = 0; // how many times we have seen new value
long time = 0; // the last time the output pin was sampled
int debounce_count = 5; // number of millis/samples to consider before declaring a debounced input
int current_state = 0; // the debounced input value

int ButtonVal;

int lift;
// = 60;
//int joypad[6]; // array – stores the values to send 

 
RF24 radio(9,10); 
//const uint64_t pipe = 0xE8E8F0F0E1LL;

const uint64_t pipes[2] = {
  0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

// default reference on circuit used (5.0, 3.3, 1.1)
const double refV = 5.0;
// How many volts does 1 ADC measure?
const double V_incr = refV/1024.0;

// values of resistances used for voltage divider
const double R1 = 68.4;
const double R2 = 46.6;

// determine voltage divider ratio
const double voltageRatio = (R2/(R1 + R2));
 
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(8, 7, 5, 4, 3, 2);

// define a type struture
// to carry lovely messages
typedef struct{
  int X;
  int Y;
  boolean buttons[4];
}
Payload;

Payload package;

typedef struct{
  int X;
  int rudderAngle;
  int Z;
}  
Feedback;

Feedback telemetrics;

void setup() {
  
  Serial.begin(57600);
  radio.begin();
  //radio.openWritingPipe(pipe);

  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);

  
  pinMode(buttonPin, INPUT);
  
  // set up the LCD’s number of COLUMNS and ROWS:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("Batt = ");
  
  lcd.setCursor(0, 1);
  lcd.print("X: ");
  
  lcd.setCursor(7, 1);
  lcd.print("Y: ");
  
}

void loop() {
  
  // monitor battery voltage on remote
  int val = analogRead(battPin);
  double battV = VoltageCheck(val);
   
  //lcd.setCursor(7, 0);
  //lcd.print(battV);
    
  package.X = analogRead(A0);
  delay(1);
  package.Y = analogRead(A1);
  delay(1);
  
  // LCD DEBUGGING
  lcd.setCursor(2, 1);
  lcd.print(package.X);
  lcd.setCursor(9, 1);
  lcd.print(package.Y);
  

   // If we have gone on to the next millisecond
  if (millis() != time)
  {
    // check analog pin for the button value and save it to ButtonVal
    ButtonVal = analogRead(buttonPin);
    delay(1);
    
    //Serial.println(ButtonVal); // DEBUG
    
    
    if(ButtonVal == current_state && counter >0)
    { 
      counter–;
    }
    if(ButtonVal != current_state)
    {
      counter++;
    }
    // If ButtonVal has shown the same value for long enough let’s switch it
    if (counter >= debounce_count)
    {
      counter = 0;
      current_state = ButtonVal;      
      //Checks which button or button combo has been pressed
      if (ButtonVal > 100){
      ButtonCheck();}else{

        package.buttons[0] = 0;
        package.buttons[1] = 0;
        package.buttons[2] = 0;
        package.buttons[3] = 0;}
    }
    time = millis();
    
  }    // closes if(millis() != time)

  //bool ok = radio.write( &duino2, sizeof(duino2) );
  // Send radio message below
  //radio.write( joypad, sizeof(joypad) );

  radio.stopListening();
  bool ok = radio.write( &package, sizeof(package) );
  radio.startListening();

  delay(20);

  //if (radio.available() )
  //{

  // Dump the payloads until we’ve gotten everything
  //uint8_t len;
  bool done = false;
  while (!done)
  {
    // Fetch the payload, and see if this was the last one.
    //len = radio.getDynamicPayloadSize();
    //done = radio.read( receive_payload, len );

    done = radio.read(&lift, sizeof(int) );

    // Put a zero at the end for easy printing
    //receive_payload[len] = 0;

    // Spew it

    //printf(“Got payload size=%i value=%s\n\r”,len,receive_payload);

    

  }

    lcd.setCursor(0,0);
    lcd.print(lift);

      // First, stop listening so we can talk
      //radio.stopListening();

  

  //}

//radio.read(&lift, sizeof(int) ); 
 
  //radio.read(&telemetrics, sizeof(telemetrics) );

// REGULAR – PREVIOUS here 
// radio.write( &package, sizeof(package) );
 
 
 
  // LCD DEBUGGING
  //lcd.setCursor(12, 0);

  //lcd.print(“L:”);

//  lcd.setCursor(0,0);
//  lcd.print(lift);

  //lcd.setCursor(0,0);
  //lcd.print(telemetrics.Z);
  //lcd.setCursor(6,0);
  //lcd.print(telemetrics.X);
  //lcd.setCursor(10,0);
  //lcd.print(telemetrics.rudderAngle);
  
  
//  lcd.print(package.buttons[0]);
//  lcd.print(package.buttons[1]);
//  lcd.print(package.buttons[2]);
//  lcd.print(package.buttons[3]);
  
  
 
}

// read that battery voltage, biaaaatch
double VoltageCheck(int v){

  double pinV = v * V_incr;
  double volts_in = pinV * 1/voltageRatio;

  return volts_in;
}

// checks which f’king button (or combo) has been pressed, if any
void ButtonCheck()
{
  // loop for scanning the button array.
  for(int i = 0; i <= 10; i++)
  {
    // checks the ButtonVal against the high and low vales in the array
    if(ButtonVal >= Button[i][j] && ButtonVal <= Button[i][j+1])
    {
      // stores the button number to a variable
      label = Button[i][0];
      
      switch (label) {
          case 1:
            package.buttons[0] = 1;
            package.buttons[1] = 0;
            package.buttons[2] = 0;
            package.buttons[3] = 0;
            //Serial.println(“button 1”);
            break;
          case 2:
            package.buttons[0] = 0;
            package.buttons[1] = 1;
            package.buttons[2] = 0;
            package.buttons[3] = 0;
            //Serial.println(“button 2”);
            break;
          case 3:
            package.buttons[0] = 0;
            package.buttons[1] = 0;
            package.buttons[2] = 1;
            package.buttons[3] = 0;
            //Serial.println(“button 3”);
            break;
          case 4:
            package.buttons[0] = 0;
            package.buttons[1] = 0;
            package.buttons[2] = 0;
            package.buttons[3] = 1;
            //Serial.println(“button 4”);
            break;
          case 5:
            //Serial.println(“button 1 + 2”);
            package.buttons[0] = 1;
            package.buttons[1] = 1;
            package.buttons[2] = 0;
            package.buttons[3] = 0;
            break;
          case 6:
            //Serial.println(“button 1 + 3”);
            package.buttons[0] = 1;
            package.buttons[1] = 0;
            package.buttons[2] = 1;
            package.buttons[3] = 0;
            break;
          case 7:
            //Serial.println(“button 1 + 4”);
            package.buttons[0] = 1;
            package.buttons[1] = 0;
            package.buttons[2] = 0;
            package.buttons[3] = 1;
            break;
          case 8:
            //Serial.println(“button 2 + 3”);
            package.buttons[0] = 0;
            package.buttons[1] = 1;
            package.buttons[2] = 1;
            package.buttons[3] = 0;
            break;
          case 9:
            //Serial.println(“button 2 + 4”);
            package.buttons[0] = 0;
            package.buttons[1] = 1;
            package.buttons[2] = 0;
            package.buttons[3] = 1;
            break;
          case 10:
            //Serial.println(“button 3 + 4”);
            package.buttons[0] = 0;
            package.buttons[1] = 0;
            package.buttons[2] = 1;
            package.buttons[3] = 1;
            break;
      } // close switch
      
    }
  }
}

 

Receiver node code:

// Lovely code for the (mostly) receiver (RX) node
#include <Servo.h>
#include <SPI.h>
#include “nRF24L01.h”
#include “RF24.h”

 
//int commands[6];

// define a type struture
// to carry lovely messages
typedef struct{
  int X;
  int Y;
  boolean buttons[4];
}
Payload;

Payload package;

typedef struct{
  int X;
  int rudderAng;
  int Z;
}  
Feedback;

Feedback telemetrics;

int oldAngle, newAngle = 0; // servo positions

long previousMillis = 0; // timer for servo
long previousButtonMillis = 0; // timer for buttons
const int interval = 30; // interval to update servo position
const int binterval = 60;

Servo rudder;

//int lift[1];

int lift_ang;

// pretty debug LEDs
const int b1 = 2;
const int b2 = 3;
const int b3 = 4;
const int b4 = 5;

// LED’s state
int b1state = LOW;
int b2state = LOW;
int b3state = LOW;
int b4state = LOW;
 
RF24 radio(9, 10);
//const uint64_t pipe = 0xE8E8F0F0E1LL;

const uint64_t pipes[2] = {
  0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

 
void setup(void)
{
  Serial.begin(57600);

  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.startListening();
  
  rudder.attach(7);
  
  pinMode(b1, OUTPUT);
  pinMode(b2, OUTPUT);
  pinMode(b3, OUTPUT);
  pinMode(b4, OUTPUT);

  digitalWrite(b3, HIGH); // DEBUG
  
  //lift[0] = 70;

  lift_ang = 70;

}
 
void loop(void)
{
  delay(10);
  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( &package, sizeof(package) );
    }
    
    // See what to do with this???
    //radio.stopListening();

    //radio.write( &duino1, sizeof(duino2) );
    //radio.startListening();
    
    
      int X = package.X;
      int Y = package.Y;

//    if (package.buttons[1] == 1 && lift[0] < 120)
//    {
//    lift[0] += 10;
//    }

//    if (package.buttons[3] == 1 && lift[0] > 70)
//    {
//    lift[0] -= 10;
//    }

//    Serial.println(lift[0]);   

    //}
      

    //radio.stopListening();
    
    //telemetrics.Z = lift[0];
    
    
    //radio.write( lift, sizeof(lift[0]) );
    //radio.write( &telemetrics, sizeof(telemetrics) );
    
    //radio.startListening();

 
    if (X > 485 && X < 525 ) // joystick is centered
    {
      newAngle = 87;     // 87 = servo in center position
    }
 
    if (X < 490)
    {
      newAngle = (map(X, 484, 140, 88, 130));
    }
 
    if (X > 530)
    {
      newAngle = (map(X, 526, 830, 86, 35));
    }

 
    unsigned long currentMillis = millis();
 
    // Issue command only if desired position changes and interval is over
    if(oldAngle != newAngle && currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      oldAngle = newAngle;
      rudder.write(newAngle); // tell servo to go to position in variable ‘pos’
  

    } // close if millis-land
  
//}
   
   
   currentMillis = millis();
   
   if (currentMillis - previousButtonMillis > binterval) {
    
    if (package.buttons[0] == 1){
      if(b1state == LOW){
      b1state = HIGH; }
      else{ b1state = LOW; }
    digitalWrite(b1, b1state);

      if(lift_ang != 90){ lift_ang = 90; }
 
    }
       
    if (package.buttons[1] == 1){
      if(b2state == LOW){
      b2state = HIGH; }
      else{ b2state = LOW; }
    digitalWrite(b2, b2state);

      if(lift_ang < 120){ lift_ang += 10; }
     
    }
        
    if (package.buttons[2] == 1){
      if(b3state == LOW){
      b3state = HIGH; }
      else{ b3state = LOW; }
    digitalWrite(b3, b3state);
    }  
       
    if (package.buttons[3] == 1){
      if(b4state == LOW){
      b4state = HIGH; }
      else{ b4state = LOW; }
    digitalWrite(b4, b4state);

      if(lift_ang > 70){ lift_ang -= 10; }
  
    }  
  
    previousButtonMillis = currentMillis;
  
    } // close if millis-land (secundary test) – button millis

    radio.stopListening();
   
    delay(20);
    
    //telemetrics.Z = lift_ang;
    //telemetrics.X = X;
    //telemetrics.rudderAng = newAngle;
    
    //if (radio.available() )
    //{
    
    radio.write( &lift_ang, sizeof(int) );
    //radio.write( &telemetrics, sizeof(telemetrics) );
    

    //}
    radio.startListening();

    //Serial.println(package.X);
    //Serial.println(telemetrics.Z);
    //Serial.println(telemetrics.X);
    //Serial.println(telemetrics.rudderAng);
    //Serial.println(“break”);
  
    //} // close while(!done)
      
  }    // close if(radio.available() )
  else { Serial.println(“No radio available”); }
  
// close loop()

Solved — sort of

Well, it works now.

What was the problem? not quite sure… but it had something to do where the radio.write() and radio.read() where being called.

What I did?

I re-organized the code in a more OCD-like manner, and once again Bajdi indirectly came to the rescue. Since, anyway I’m following is footsteps on using the nRF24L01+ modules I went and check out is code at:

http://www.bajdi.com/dagu-rover-5-remote-control-with-nrf24l01/

And carefully extracted and merged the relevant RF24 code into my own… and after a while… overall success.

I now both have responsiveness and I receive the telemetry data back to… there’s only an issue with the RX node voltage reading, but I’m assuming it’s physical manufacturing problem of the board, and anyway for the current project I’ll be reading the hover battery voltage some other way :smiley: