4
\$\begingroup\$

I'm using an Arduino for sensor readings and sending them to a Raspberry Pi via USB, using PySerial for data reception.

It works great, except for the fact received data is awkwardly modified (And set as constant). For example, I'm reading voltages and calculating currents. The results on the Arduino serial are as follows:

Volt   Current
4.93   0.38
4.92   0.37
4.92   0.37
4.92   0.36
...    ...

However, on the Raspberry Pi, it's constantly read as follows (Notice how the digits are changed to zero):

  Volt   Current
    4.99   0.30
    4.99   0.30
    4.99   0.30
    4.99   0.30
    ...    ...

I've tried several turnarounds, but with no luck. I'm not sure where the problem lies, as I am very confident my code is flawless. I even converted the readings to string before sending and yet the constant readings and zero'd digits keep appearing. I appended a counter integer which was sent correctly with no problems.

Has anyone ever tried this before? Any thoughts on how to solve this?

Raspberry Pi Code:

from time import gmtime, strftime
import time
import serial
import struct
ser = serial.Serial('/dev/ttyACM1', 19200)
f = open('results.txt','w')

while 1:
        temp=strftime("%Y-%m-%d %H:%M:%S", gmtime())+'\t'+ser.readline()
        print(temp)
        f.write(temp)
        f.close()
        f = open('results.txt','a')
        time.sleep(5)

Arduino Code:

...

  double volt = 5.0*(analogRead(A0))/1023.0;

  double current = 5.18 - temp;   //Resistance ~= 1 Ohm if you are wondering

  buffer += d2s(volt,2)+'\t'+d2s(current,2)+'\t'+ d2s(count,0) +'\t' + d2s(minCount,0);

  Serial.println(buffer);

...

//I got this from the web

String d2s(double input,int decimalPlaces){

  String string;

  if(decimalPlaces!=0){
    string = String((int)(input*pow(10,decimalPlaces)));

       if(abs(input)<1){
          if(input>0)
              string = "0"+string;
          else if(input<0)
              string = string.substring(0,1)+"0"+string.substring(1);
  }

  return string.substring(0,string.length()-
decimalPlaces)+"."+string.substring(string.length()-decimalPlaces);
}

   else {
     return String((int)input);

}
}
\$\endgroup\$
  • \$\begingroup\$ Can you show the relevant code snippets in both ends? \$\endgroup\$ – Alejandro Mar 10 '13 at 17:36
  • \$\begingroup\$ Done... Take a look \$\endgroup\$ – Ahmed Farid Mar 10 '13 at 17:57
  • \$\begingroup\$ A general attack on problems of this sort is to test doing everything to and from text files rather than live streaming data sources. So for example you would capture the arduino output to a text file, verify visually that it is correct, then process that with the python program and verify that the output matches the input. Likely you have a parsing or printing problem with floating point values... \$\endgroup\$ – Chris Stratton Mar 10 '13 at 18:55
  • \$\begingroup\$ Where are you configuring the the Arduino's UART? \$\endgroup\$ – Alejandro Mar 11 '13 at 2:27
  • \$\begingroup\$ @Chris I currently don't have access to an SD card adapter for the arduino, but I'll definitely give a try \$\endgroup\$ – Ahmed Farid Mar 11 '13 at 5:47
1
\$\begingroup\$

The arduino is not well suited to doing floating point math, nor is it partiularly well suited to doing string manipulation.

You would be better off by sending the value read from the analog input directly to the python code on the Pi and do the math and string manipulation in Python.

On the arduino side just do something like this:

int value;

value = analogRead(A0); // reads a 12bit integer value from the Analog input
Serial.println(value);  // converts the integer to a string and sends it over the serial port

Then on the Pi side:

str = ser.readline()  # read a string from the serial port

value = float(str)    # convert a string to a floating point number

volt = 5.0 * value / 1023.0  # compute the voltage
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Why didn't I think of that?! I knew the integers were sent correctly, all I needed was just to convert them on the other side. Quick, simple, and works. Thanks a lot! \$\endgroup\$ – Ahmed Farid Mar 17 '13 at 8:49
  • \$\begingroup\$ Although I still got to find out about the issue of the Pyserial not reading the floating-point strings correctly in the first place. \$\endgroup\$ – Ahmed Farid Mar 17 '13 at 8:50
0
\$\begingroup\$

I found a way to send the information correctly using Serial.write(), but apparently it works byte-by-byte. Thus, I'l have to write some more code to translate each and every byte.

I'm sure there's a better and easier way though.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Note: Sending an array of bytes didn't work \$\endgroup\$ – Ahmed Farid Mar 14 '13 at 8:10
0
\$\begingroup\$

If you're suspecting the PySerial library, I have to say I'd be really suprised if the issue is there.

I've used PySerial pretty extensively, for both binary and ascii data without issues (though not on a Raspberry Pi).

One thing I can think of is it's possible the port is opening in a weird mode. Try manually specifying the parity and stop-bits mode:

ser = serial.Serial('/dev/ttyACM1', baudrate=119200, bytesize=8, parity='N', stopbits=1)

The other thing I can think of is that you're somehow sending an ASCII control-code, which PySerial is interpreting properly, and the Arduino terminal isn't.
If possible, try an additional serial terminal, and see if it agrees with one or the other.


Honestly, this really smells like a RAM issue to me. You're using a lot of C++ functions (std::string), which are very RAM hungry. You should really think of the arduino as a C device, and avoid C++ abstractions, if possible.

Also, Why the heck are you using doubles? The ADC precisions is 12 bits! A plain-old float is 32 bits on the arduino.

Also you're confident your code is "flawless", which smacks of inexperience to me (the only perfect code is code that doesn't exist).
Together with that (very sloppy) hack of a double to string conversion function (that you found on the internet!), makes me suspect the arduino code more.

Please post your whole arduino source, not just a snippet, too.


Another thing to try is just to store and print some of your results as pure strings:

Serial.println("4.93   0.38")
Serial.println("4.92   0.37")
Serial.println("4.92   0.37")
Serial.println("4.92   0.36")

If that fails, it is indeed likely it's a problem in PySerial. If it doesn't, it's the arduino code.

| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

Actually, pyserial reads data from the Arduino as bytes, e.g.: b234\r\n. So you need to strip those unnecessary values before you can use them:

 valuebtw0to1023= serialObj.readline().strip('\r\n').strip()
| improve this answer | |
\$\endgroup\$
0
\$\begingroup\$

if you plan to read serial data from al APC220 RF antenna with python, you will have to add the line :

ser = serial.Serial('/dev/ttyACM1', 19200)
ser.setRTS(0) #  <------------------- this line solve the problem

I found it after a whole day of try-error.

| improve this answer | |
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.