Pages: [1]   Go Down
Author Topic: Reading an int value from Arduino with pySerial  (Read 2165 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I am currently trying to read the speed of a DC motor with pySerial. It works well if I just pring the value on the serial monitor, but when I try to read it with Python is returns weirds hexadecimal values. Here is the part of the code on the Arduino :

Code:
// Return the motor speed
    if (input == 'g')
    {
      // Init measurement values
      motor_speed_meas = 0;
      motor_speed_mean = 0;
    
      // Take 10 measurements and average
      for (int i=0;i<10;i++)
      {
        motor_speed_meas = motor_speed_meas + 500000/(float)pulseIn(7, HIGH);
      }
      
      motor_speed_mean = (int)(motor_speed_meas/10);
      
      // Write on the serial
      Serial.write(motor_speed_mean);
    }

And then the code I am using on Python :

Code:
import serial
import time

ser = serial.Serial('/dev/tty.usbmodemfd121', 9600)

time.sleep(1)

def read_speed():
ser.write("g")
time.sleep(0.01)
speed = ser.read()

return speed

I just made a test that gradually increases the speed of the motor, and measure the speed with the Python interface. Here is the result :

Code:
['\x90',
 '\xc5',
 '\xf5',
 '\x1b',
 '=',
 '\\',
 'v',
 '\x8d',
 '\xa2',
 '\xb4',
 '\xc3',
 '\xcf',
 '\xdd',
 '\xea',
 '\xf3',
 '\xfd',
 '\x05',
 '\x0c',
 '\x15',
 '\x1a']

This return values that doesn't make sense, whereas it is correct if I just use Serial.print() on the Arduino. What am I doing wrong ?

Thanks !
« Last Edit: March 03, 2012, 07:58:48 am by marco26 » Logged

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

When you use Serial.write() to send data, it sends data in binary. The Serial class only has one write() method, and that method takes a uint8_t (also known as a byte). So, the most significant byte of your int gets discarded, limiting you to 256 values, from 0 to 255.

If you want to sent the int in binary, you need to send the most significant byte first, then the least significant byte, using two calls to Serial.write() (and the highByte() and lowByte() methods or bit shifting and masking).

On the python side, you need to read both bytes and put them back together.

Or, send the data as a string.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13668
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just as PaulS said:

Arduino sends 2 bytes.
Code:
Serial.write(motor_speed_mean / 256);
Serial.write(motor_speed_mean % 256);

Python must read 2 bytes and merge them
Code:
import serial
import time

ser = serial.Serial('/dev/tty.usbmodemfd121', 9600)

time.sleep(1)

def read_speed():
ser.write("g")
time.sleep(0.01)
speed = ser.read() * 256;
        speed = speed + ser.read()
return speed

With binary data it is good practice to send delimiters with the stream. Start & stop symbols help to get the datastream in sync again if connection loses a byte
e.g. <bytebyte> the < is a start char byte byte are 2 bytes and teh > is a stop char. A combination of >< identifies the begin of new data.
Furthermore it is good practice to send an identifier too.
< ID B B B B >  e.g. some measurement that needs a long The first byte after the start symbol is the identifier byte. For speed this could be 'S' for RPM 'R' for Gas 'G' etc

A step further is to add a checksum ==> < ID B B B B C > The byte C is a value from a formula processing all bytes in one packet.''

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

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

Thanks a lot for the answers, I implemented the changed suggested by robtillaart, but I still have a last problem, here is an example of what I get in Python :

Code:
'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01w'

How can I convert this back to a number ?

Thanks
Logged

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

Do you know enough about python to make it print each new value on a new line? It's hard to see what that mess corresponds to. We can't see over your shoulder, and see that you implemented rob's suggestions correctly, either.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13668
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


You must add a counter how many bytes you received, and every 60 character you print a newline CRLF and reset the counter. (just like the good old lineprinter smiley



Furthermore it is not good programming t use time.sleep() in python, as you block the process manually. Furthermore it is overkill as serial.Read() allready blocks until it reads 1 byte (the Timeout flag is default set none) - http://pyserial.sourceforge.net/pyserial_api.html#module-functions-and-attributes -

Code:
import serial
import time

ser = serial.Serial('/dev/tty.usbmodemfd121', 9600)  -- default timeout = none

time.sleep(1)
def read_speed():
ser.write("g")
speed = ser.read(1) * 256;
        speed = speed + ser.read(1)
return speed


Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

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

Thanks to all, it works perfectly now !
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 216
Posts: 13668
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Can you post your complete python script for reference...
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: