Reputation: 1191
I have a python script that communicates with an arduino over serial. It works as expected on my computer but when I run the script on my Raspberry Pi, it does not work. It gets stuck after printing "Sent: 1". I think it is stuck waiting for one byte from the arduino (first line from sendValue). However, I don't know why this is happening as it works fine running it from my computer or the Pi's serial monitor.
Python script:
import serial
ser = serial.Serial('/dev/ttyACM0', 9600)
def sendValue(value):
ser.read(1) # Arduino will send one byte when it's ready for the value
ser.write(value) # Send value
print("Sent: {}".format(value))
return;
ser.write('1') # Select function '1'
print("Sent: 1")
sendValue('5000') # Send 1st parameter to function '1'
sendValue('4000') # Send 2nd parameter to function '1'
while True:
print(ser.readline())
Arduino code:
int task = 0;
int val = 0;
int val2 = 0;
int val3 = 0;
void task1(int length){
Serial.println(length);
digitalWrite(13, HIGH);
delay(length);
digitalWrite(13, LOW);
}
void task2(int length1, int length2){
Serial.print("Running task2 with parameters ");
Serial.print(length1);
Serial.print(" and ");
Serial.println(length2);
digitalWrite(13, HIGH);
delay(length1);
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
delay(length2);
digitalWrite(13, LOW);
}
void waitForSerial(){
while(Serial.available() == 0);
}
int getValue(){
Serial.write(48);
waitForSerial();
return Serial.parseInt();
}
int getCommand(){
if(Serial.available() == 0){
return -1;
}
String in = "";
in += (char)Serial.read();
return in.toInt();
}
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
task = getCommand();
switch(task){
case 0:
val = getValue();
task1(val);
val = 0;
break;
case 1:
val = getValue();
val2 = getValue();
task2(val, val2);
val = val2 = 0;
break;
}
}
I have tried putting a delay in instead of the ser.read(1)
where I think it is getting stuck but that still doesn't work.
I could not decide whether to put this on the Raspberry Pi community or Arduino community so I put it here.
Upvotes: 1
Views: 802
Reputation: 1081
You may have an issue related to the Arduino auto-reset. When the Arduino is reset, it takes a few seconds to "reboot" and start running its main program (loop()
). When you connect to an Arduino with a Unix OS (e.g. Raspberry Pi), it triggers the auto-reset. If your Python script immediately sends data to the Arduino after the connection, this data may get captured by the boot loader instead of the Arduino processor code because the processor is not ready, so the Arduino acts like nothing is happening. You might not see this behavior if you test the Arduino on Windows; some Windows configurations do not trigger the auto-reset on the initial connection, and the same for the serial monitor.
My solution is simply to add a delay of 5 seconds after the serial connection is created in your python script, but before any data is transmitted. If this solves the problem, then you can get more creative about solutions to tell the host when the Arduino is ready. For example, you can print a line to the host at the end of the setup()
portion of the Arduino sketch (Serial.println('READY');
). You can also put a few lines of code that makes the onboard LED blink at the end of the setup()
routine, as a visual cue for troubleshooting:
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
delay(150);
digitalWrite(13, LOW);
delay(150);
digitalWrite(13, HIGH);
delay(150);
digitalWrite(13, LOW);
When you see the double-blink, you know the processor is ready to receive communication from your host program.
Upvotes: 1
Reputation: 1191
A better way to do this would be to use the fact that an invalid character given so Serial.parseInt()
, parsing stops.
Initial characters that are not digits or a minus sign, are skipped; Parsing stops when no characters have been read for a configurable time-out value, or a non-digit is read; If no valid digits were read when the time-out (see Serial.setTimeout()) occurs, 0 is returned;
https://www.arduino.cc/en/Reference/ParseInt
Then you could do something like this:
var1 = Serial.read();
var2 = Serial.read();
var3 = Serial.read();
and in python:
ser.write('<number1>a<number2>a<number3>a')
Upvotes: 1