Hi, I have a project where I control the Arduino from a RasPi. A python program listens for incoming messages from an MQTT queue and dispatches commands to the Arduino. Since I am using Servos, I need to wait for the commands to complete before new commands are issued.
Here's a YouTube video showing how it worked before I used GPIO: The movements are jerky and it takes ages from I throw a switch in Minecraft until the eyes in the skull turn off: The real skull sees you in minecraft! - YouTube
When I used USBSerial, the roundtrip time was a full second, no matter how simple the command was (like turning on a LED). I asked around, and was told to use GPIO. I then purchased a logic converter from Adafruit and used the SoftSerial library on the Arduino. The speed increase was dramatic! Now the roundtrip time can be measured in miliseconds. Why is this so?
The code is almost unchanged, I just had to adjust for the limitations in the SoftSerial library compared to Serial object.
I have extracted the before and after code in two gists:
Without spending more time than I am prepared to do I can't figure out from your code what "round trip" you are having a problem with.
I haven't found any problem using the normal USB serial connection - as far as I recall it worked up to 1 megabaud in a test - apart from the normal USB latency, but that's only about 1 millisecond.
I have a working project that transmits and receives 5 times per second quite reliably.
Perhaps all of the delay()s in your code are the problem?
Have you experimented with a simple piece of code (in both Python and Arduino) that tests the round trip performance with no other distractions?
Roundtrip: Time it took from the command was sent to the Arduino until I got a reply back. Before GPIO it was > a second. (see line 31 onwards in dispatcher.py
After changing the code to use GPIO it was like a half millisecond. No other changes were made, (Yes I have added some more functionality later, but not before I measured the new results)
Some delays are there to allow the servos to move, btw. Other delays may or may not be necessary, byt again: they are the same as before.
Yes I tested the code without other distractions like the MQTT queue, and the results were the same.
sisomm:
Roundtrip: Time it took from the command was sent to the Arduino until I got a reply back. Before GPIO it was > a second. (see line 31 onwards in dispatcher.py
I was hoping you would describe the steps involved in the round trip so I wouldn't have to read the code?
OK:On the Python I send simple commands to the Arduino and wait for response. The loop below performs at least 1000 times faster with SoftSerial on the other side. No other changes were made in the communication, bar using a '|' as a command terminator
arduino.write(command)
response=''
ack=False
while not ack:
response=arduino.readline()
if (len(response)>0):
ack=True
end=time.time()
print('Response to {} took {:G} millis'.format(response.strip(),(end-start)*1000))
Actually, before I used Python it was blazingly fast. I just used shell commands on the mac and piped things in and out of the queue. this didn't work for raspi, and besides i needed to wait for ack. But it was fast!
I think this is a problem with the raspberryPi end of things. It is the Linux that slows things down and the Python also adds a lot to the delays.
I have a project where I am sending bytes at a rate of 40 per second from the Arduino to the Pi through the USB serial port and while the Pi keeps up sometimes there is 4K of data in the buffer waiting to be processed.
## How it was with Serial
if(not commands.empty()):
command=commands.get()
if(args.verbosity>0):
print("DISPATCHER: sending to Arduino: "+command)
start=time.time()
arduino.write(command)
# wait until we get OK back
response=''
ack=False
while not ack:
response=arduino.readline()
if (len(response)>0):
ack=True
end=time.time()
print('Response to {} took {:G} millis'.format(response.strip(),(end-start)*1000))
## How it is with SoftSerial
while True:
if(not commands.empty()):
command=commands.get()
if(args.verbosity>0):
print("DISPATCHER: sending to Arduino: "+command)
start=time.time()
arduino.write(command+'|')
# wait until we get OK back
response=''
ack=False
while not ack:
response=arduino.readline()
if (len(response)>0):
ack=True
end=time.time()
print('Response {} to {} took {:G} millis'.format(response,command,(end-start)*1000))