2

I have got a question about serial communication between Arduino and Raspberry Pi. The fact is I want to send 2 variables to Raspberry Pi with Arduino and use them in different ways.

Here my sketch for Arduino :

int one = 1;
int two = 2;

void setup() 
{

     Serial.begin(9600);
}

void loop() 
{
   Serial.print(one);
   Serial.print(two);
   delay(3000);

}

Here my python script for Raspberry:

import serial
import time

ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(4)

while True:
    data=ser.read()
    print data

The problem is that 'data' in the python code takes the two values send by Arduino (because of two print in the Arduino loop() ). But I want to receive the datas in Raspberry Pi with two different variables (to record them after). I try many technics to receive these datas in two different ways, but it not work.

Thank you for your help.

3 Answers 3

3

Arduino's Serial.print sends data as ASCII. So your commands from the Arduino actually send the string 12. There is no way for Python do see where the first value ends and where the second one begins.

One solution is to use Serial.println instead of Serial.print. This will add a carriage return and a newline after each call. So the string will become 1\r\n2\r\n.

On the Python side you can then use the split method. An example in IPython:

In [1]: recv = "1\r\n2\r\n"

In [2]: recv.split()
Out[2]: ['1', '2']

And you can then easily convert the values to integers.

In [3]: [int(j) for j in recv.split()]
Out[3]: [1, 2]

Note: it is possible for Python to get an incomplete message! So you just might receive the string 1 the first time you read and 2 during a second read! So you might want to consider formatting your data so you know you have received a complete message.

One option to do that is to format your data as JSON. In your example this would be {"one": 1, "two": 2}. In this simple calse you can check that you have received a complete message because it starts with a { and ends with a }. But you could also use Python's built-in JSON parser.

In [4]: data = {'one': 1, 'two': 2}

In [5]: import json

In [6]: json.dumps(data)
Out[6]: '{"two": 2, "one": 1}'

In [7]: recv2 = json.dumps(data)

In [8]: json.loads(recv2)
Out[8]: {'one': 1, 'two': 2}

Using the JSON parser has an advantage because it raises an exception when you try to parse an incomplete message:

In [10]: recv2
Out[10]: '{"two": 2, "one": 1}'

In [11]: recv3 = '{"two": 2, "on'

In [12]: json.loads(recv3)
---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
<ipython-input-12-c1774b41dafa> in <module>()
----> 1 json.loads(recv3)

/usr/local/lib/python3.5/json/__init__.py in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    317             parse_int is None and parse_float is None and
    318             parse_constant is None and object_pairs_hook is None and not kw):
--> 319         return _default_decoder.decode(s)
    320     if cls is None:
    321         cls = JSONDecoder

/usr/local/lib/python3.5/json/decoder.py in decode(self, s, _w)
    337 
    338         """
--> 339         obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    340         end = _w(s, end).end()
    341         if end != len(s):

/usr/local/lib/python3.5/json/decoder.py in raw_decode(self, s, idx)
    353         """
    354         try:
--> 355             obj, end = self.scan_once(s, idx)
    356         except StopIteration as err:
    357             raise JSONDecodeError("Expecting value", s, err.value) from None

JSONDecodeError: Unterminated string starting at: line 1 column 12 (char 11)

The correct way to deal with this is to keep reading data from the serial port and appending it to a string until parsing the data doesn't fail;

import serial
import json
import time

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

buffer = ''
while True:
    buffer += ser.read()
    try:
        data = json.loads(buffer)
        print(data)
        buffer = ''
    except json.JSONDecodeError:
        time.sleep(1)
Sign up to request clarification or add additional context in comments.

Comments

0

Re,

In first I want to thank you for your answer and to make me discover Json. So I tried your last python code and modify my Arduino code like this :

int one=1;
int two=2;
int three = 3;
int four = 4;

void setup() {
  Serial.begin(9600);
}

void loop() {
    Serial.println("{\"one\":\"" + String(one) +
    "\", \"two\":\"" + String(two) +
    "\", \"three\":\"" + String(three) +
    "\", \"four\":\"" + String(four) +
    "\"}");
}

In raspberry Py when i execute the code (without a while), the console return nothing. It seems that data send juste one character.

Thanks again

1 Comment

Please do not post additional questions as answers. Edit your question instead. Also, the numbers in JSON don't need quotes.
0

Actually I am quite new in these applications but I accidentally found a way straightforward.

Well of course, Roland's answer already does the job perfectly. This solution can basically do-it-very-fast.

After writing these two lines below in Arduino;

   Serial.print(one);
   Serial.print(two);

Just go and read the lines in Raspberry with the same way;

   ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
   ser.flush()

   one = ser.readline().decode('utf-8').rstrip()
   two = ser.readline().decode('utf-8').rstrip()

I think the trick here putting two readline() subsequently read the lines printed by Arduino in accordance. At least it worked for me :)

Well, I am not expert, just a beginner.

Salutations,

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.