Pages: [1]   Go Down
Author Topic: Sending 2 byte integer to Arduino  (Read 2159 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I'm having a little bit problems while trying to send 2 byte integer to arduino. This is for controlling servo. Here's sending part on PC:

Code:
// Servo motor function
bool SerialDriver2dof::moveServoMotor(int position){
char message[5];

int pos1 = 0, pos2 = 0;
pos1 = position & 0xFF;
pos2 = (position >> 8) & 0xFF;

message[0] = '*'; /// msg starting symbol
message[1] = 'B'; /// B for servo motor
message[2] = (char) pos1; /// position for servo
message[3] = (char) pos2;
message[4] = ';'; /// Ending symbol for msg

dPrint(1,"Message: %c %c %c %c", message[0], message[1], message[2], message[3]);
if(Write((char*)message, 5) == false){
return false;
}
else{
return true;
}
}

And here's arduino receiving and parsing that 2 byte integer back together, case B:
Code:

void loop(){
   while (Serial.available() > 0 && !msgEnd && msgPointer < MSG_LENGTH ) {
    message[msgPointer] = Serial.read();    //character from PC
             if(msgPointer == 0 && message[0] != '*'){
                 break;
             }    
             if (message[msgPointer] == MSG_END){
                msgEnd = true;
             } else {
                msgEnd = false;
                msgPointer++;
             }
             if(msgPointer >= MSG_LENGTH){
                msgEnd = true;  
             }
       }  
        
       if (msgEnd == true) {                            // message received
           if(message[0] == '*'){                       // check that has msg at the beginning
               switch(message[1]){                    
                    case 'B':                                // SERVO            
                        pos1 = (message[2] << 0);
                        pos2 = (message[3] << 8);
                        pos = (pos2|pos1);
                        moveServo(pos);
                        received();
                        break;
                    case 'R':
                        resetValues();
                        received();
                        break;
                    default:
                        error();
                        break;
               }
           }else{
           Serial.print("ERROR: Unknown message no START * ");
                  Serial.print("Message: ");
                  Serial.println(message);
          }    
          
           msgEnd = false;
           msgPointer = 0;
          
           // empty msg variable      
           for (int i=0; i < MSG_LENGTH; i++) {          
             message[i] = 0;
           }
       }
}


But i'm unsure if this is going as it should be. There is correctly functioning serial listening part for starting symbol and ending symbol. It works for simple cases where i just send one char but not for numbers.

Is this correct way to receive 2 BYTE integer for arduino? seems like it's not... any help would be greatly appreciated!

EDIT: corrected char message[5]
« Last Edit: May 20, 2011, 07:56:01 am by ajr_ » Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 533
Posts: 26941
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

char message[4];  is only 4 bytes
but then you define 5 addresses.

Why not just define your variables as bytes to match your array?
I don't see where pos1 and pos2 ever get to be anything but 0.

I could see this working with a little more effort. Can you post the complete code for both?


Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

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

Corrected that typo, but it didn't fix the problem. Isn't pos1 and pos2 receiving parts of original int from PC by (char) message[2] and [3] ?
What you mean by defining my variables as bytes? I'm not very experienced with arduino. You mean it's a problem if i define pos1 and pos2 as ints?

Here's not all cases but parts which servo is using.

Code:
#include <avr/interrupt.h>
#include <Servo.h>

#define MSG_LENGTH 12
#define MSG_END ';'
#define MSG_START '*';










//======================================================================//
// //
//                   VARIABLES //
// //
//======================================================================//

//======================================================================//
//                   SERIAL //
//======================================================================//

//HardwareSerial Uart = HardwareSerial();


char message[MSG_LENGTH];    // character where to store information
int msgPointer = 0;

bool msgEnd;

char messageReceived[3];
char messageError[3];


//======================================================================//
//                   SERVO         //
//======================================================================//
Servo myservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position
int servoPin = 27;  // pin for servo PWM signal
int pos1 = 0;
int pos2 = 0;


//======================================================================//
//                     SWITCH      //
//======================================================================//

int switchPinOne = 19;
int switchPinTwo = 18;
// volatile because accessible variable outside ISR
volatile int leftSwitch = 0, rightSwitch = 0; 





//======================================================================//
//======================================================================//
//======================================================================//
//======================================================================//
//======================================================================//








//======================================================================//
// //
//                   SETUP         //
// //
//======================================================================//

void setup(){
  Serial.begin(9600);
 
 // empty msg variable     
 for (i; i < MSG_LENGTH; i++) {         
   message[i] = 0;
 }

//======================================================================//
//                   SERVO                 //
//======================================================================//
  myservo.attach(servoPin);             // attaches the servo on pin 9



 
//======================================================================//
//                     SWITCH      //
//======================================================================//
 
  pinMode(switchPinOne, INPUT);
    digitalWrite(switchPinOne, HIGH);        // turn on pull up resistor
  pinMode(switchPinTwo, INPUT);
    digitalWrite(switchPinTwo, HIGH);        // turn on pull up resistor
 
  attachInterrupt(switchPinOne, switchDetectedOne, RISING);  // left bank E7
  attachInterrupt(switchPinTwo, switchDetectedTwo, RISING);  // right bank E6
 
 
 
  // start with stepper with sleepmode !!
  sleep();
 
}

//======================================================================//
// //
//                   SERVO FUNCTIONS        //
// //
//======================================================================//
void moveServo(int pos){
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(500);                       // waits 15ms for the servo to reach the position
}




//======================================================================//
//======================================================================//

void received(){

  messageReceived[0] = MSG_START;
  messageReceived[1] = '>';
  messageReceived[2] = MSG_END;
 
  //for(j = 0; j<5;j++){
    Serial.print(messageReceived);
  //}
}

void error(){
 
  messageError[0] = MSG_START;
  messageError[1] = '<';
  messageError[2] = MSG_END;
 
  //for(j = 0; j<5;j++){
    Serial.print(messageReceived);
  //}
}




//======================================================================//
// //
//                   RESET FUNCTION        //
// //
//======================================================================//
void resetValues(){

  //encoder values
  turn = 0;
  turn0 = 0;
  turn1 = 0;
  turn2 = 0;
  decimal = 0;
 
  //msg received & error counters
  i = 0;
  j = 0;
 
  //stepper
  a = 0;
  b = 0;
  c = 0;
  d = 0;
 
  //servo
  pos1 = 0;
  pos2 = 0;
  pos = 0;
 
  // switch variables
  leftSwitch = 0;
  rightSwitch = 0;
 
  //Serial flush
  Serial.flush();
}

//======================================================================//
//======================================================================//
//======================================================================//
//======================================================================//
//======================================================================//
// //
//                   MAIN LOOP         //
// //
//======================================================================//

void loop(){
       
        //Serial.println(msgPointer);
  while (Serial.available() > 0 && !msgEnd && msgPointer < MSG_LENGTH ) {
     message[msgPointer] = Serial.read();    //character from PC
             if(msgPointer == 0 && message[0] != '*'){
                 break;
             }   
             if (message[msgPointer] == MSG_END){
                msgEnd = true;
             } else {
                msgEnd = false;
                msgPointer++;
             }
             if(msgPointer >= MSG_LENGTH){
                msgEnd = true; 
             }
         
       } 
   
       if (msgEnd == true) {                            // message received
           //Serial.println("Parsing message and executing cmd...");
           if(message[0] == '*'){                       // check that has msg at the beginning
               switch(message[1]){                     
                    case 'B':                                // SERVO             
                        pos1 = (message[2] << 0);
                        pos2 = (message[3] << 8);
                        pos = (pos2|pos1);
                        moveServo(pos);
                        received();
                        break;
                    case 'S':
                        sleep();
                        received();
                        break;
                    case 'W':
                        wakeUp();
                        received();
                        break;
                    case 'R':
                        resetValues();
                        received();
                        break;
                    default:
                        error();
                        break;
               }
           }else{
           Serial.print("ERROR: Unknown message no START * ");
                  Serial.print("Message: ");
                  Serial.println(message);
          }   
           
           msgEnd = false;
           msgPointer = 0;
           
           // empty msg variable     
           for (int i=0; i < MSG_LENGTH; i++) {         
             message[i] = 0;
           }
       }


}
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49037
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sometimes reading the documentation is good. Sometimes it isn't sufficient, though.

Your servo is sent to some position using the Servo::write() method. What physical limits exist for your servo? Typically, a servo is limited to 0 to 180 degrees (or less).

The values that a servo can physically move to, when expressed as integer values can fit in a byte, which can hold a range of values from 0 to 255. Since that is greater than the servo can actually move to, a byte is generally sufficient. And, much easier to send to the Arduino.
Logged

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

I could probably handle servo with one byte, but i also got implementation with stepper motor where i need more values than 255. That case has basically same problem for transferring multiple bytes (4).

Also this exactly same solution works flawlessly with encoder other way around, from arduino to PC, but for some reason not from PC to arduino. Main question is about merging bytes on arduino end. Am I doing it correctly..? If so, then the problem is somewhere else.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49037
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you print the values of pos1 and pos2 on the PC and Arduino, do they match?

Quote
Main question is about merging bytes on arduino end. Am I doing it correctly..?
Doesn't look right to me. You are shifting the high order byte back to the high position and or-ing that with the low order byte. Usually the high order byte is ADDED to the low order byte.
Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 360
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your Processing code is using a 4-byte signed integer (32 bits), not a 2-byte signed integer as you would expect.  Trying using a 'short' instead.
If you print the values of pos1 and pos2 on the PC and Arduino, do they match?

Quote
Main question is about merging bytes on arduino end. Am I doing it correctly..?
Doesn't look right to me. You are shifting the high order byte back to the high position and or-ing that with the low order byte. Usually the high order byte is ADDED to the low order byte.

A bitwise OR is perfectly valid, in this case. 

For example, if pos1 = 0B00001111 and pos2 = 0B10101010

pos2 = pos2 >> 8: pos2 = 0B1010101000000000
pos1 + pos2 = 0B0000000000001111 + 0B1010101000000000 = 0B1010101000001111
pos1 | pos2 = 0B0000000000001111 | 0B1010101000000000 = 0B1010101000001111

This is valid because there is no carry operation performed by the addition, and there should not be a carry operation.  It is arguable that the bitwise operation is preferred, because it keeps the entire thing in bit-by-bit logic, instead of allowing for carry operations, which may change surrounding bits.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 610
Posts: 49037
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Your Processing code is using a 4-byte signed integer (32 bits), not a 2-byte signed integer as you would expect.  Trying using a 'short' instead.
This is why lots of people need to look at the code. I knew this; it just didn't register...
Logged

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

I have tried both int and short int. It doesn't make a difference, but if i'm correct it shouldn't make a difference. While using int i just waste 2 bytes but they are full of zeroes in my case?

Anyway i tried the following to figure out what is wrong. On arduino printed some values back, 5 printings and msg received symbol combination *>;
Code:
                   case 'B':                                // SERVO
                        //Serial.println("case b");
                        pos1 = message[2];
                        pos2 = message[3];
                        Serial.write(pos1);  // sama luku1
                        Serial.write(pos2);  //smaa luku2          
                        pos1 = (message[2] << 0);
                        pos2 = (message[3] << 8);
                        pos = (pos2|pos1);
                        moveServo(pos);
                        Serial.write(pos & 0xFF);  //sama luku1
                        Serial.write(pos >> 8);  //sama luku2
                        Serial.print(pos); // 22 512

And with following ASCII input *B22;
Code:
*            B             2            2            ;
2A          42           32           32          3B
042         066         050         050         059
00101010    01000010    00110010    00110010    00111011

I'll get this output from arduino:
Code:
ASCII
2 2 2 2 1 2 8 5 0 * > ;
HEX
32 32 32 32 31 32 38 35 30 2A 3E 3B
Decimal
050 050 050 050 049 050 056 053 048 042 062 059
Binary
00110010 00110010 00110010 00110010 00110001 00110010 00111000 00110101 00110000 00101010 00111110 00111011

I'll get 12850, but i should be getting 514?
Last *>; combination is just symbol combination for receiving message from arduino.
« Last Edit: May 20, 2011, 06:42:27 am by ajr_ » Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 299
Posts: 26196
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
12850
is 0x3232 or the same as '22' in ASCII - are you missing a conversion stage somewhere?
Like subtracting '0'.
« Last Edit: May 20, 2011, 06:51:49 am by AWOL » Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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

Quote
12850
is 0x3232 or the same as '22' in ASCII - are you missing a conversion stage somewhere?
Like subtracting '0'.
Hmm, used hterm to capture this output. But if that's correct, then everything should work? Arduino is getting my short int from PC by two bytes and merging those back to one short int variable called pos? If on arduino I pass this pos value to servo.write(pos) function, servo should move accordingly?
Of course in servo case by using values between 0-180.
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 299
Posts: 26196
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If on arduino I pass this pos value to servo.write(pos) function, servo should move accordingly?
But if you're pass the servo write a value of 12850, that isn't going to work.

Are you saying you expect the servo to go to position 22 decimal?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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

Quote
If on arduino I pass this pos value to servo.write(pos) function, servo should move accordingly?
But if you're pass the servo write a value of 12850, that isn't going to work.

Are you saying you expect the servo to go to position 22 decimal?
Nope, that most recent post was just an test to see does arduino receive correctly what i'm sending and replying it back to me from serial monitor program. If i'm dividing short int = 100 to two bytes, send to arduino. Merge it on arduino to short int pos variable and pass that to servo function everything should work, but it doesn't.. well, i guess got to keep debugging..

EDIT: OK seems like arduino is receiving correctly what is sent to it through Hterm. Problem is most likely on Linux sending function..
« Last Edit: May 20, 2011, 08:54:02 am by ajr_ » Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 360
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I hope you realize that if you send the data in one direction with ASCII and read it as if it were sent in binary, you'll never get the conversions correct.  You are sending, in decimal form, two bytes, both of value '50'.  50 << 8 + 50 = 12850, so your code is working as expected.  What you NEED to do is figure out how to send in binary instead of ASCII notation - What language is your 'sender' code in? I just realized it's not Processing, and is some variant of C/C++.
Logged

Pages: [1]   Go Up
Jump to: