France
Asked
Resolved Resolved by DJ Sures!

Python Script For The Roomba - UART.Hardwareuartread Issue

Hi,

I am continuing my EZ-scripts to Python conversion and I have begin to work on my Roomba robot. All my command work with the EZ-scripts, but some of them don't with Python. I have in particular some difficulties with the reading of UART data.

Here are some part of scripts used to identify the Roomba working mode:

With EZ-Script


uartinit(0, 1, 115200) #have to have this to clear the buffer
sleep(1000)
$rxdata=0
uartWrite(0,1,142) # Mode check
uartWrite(0,1,35) # Mode check
sleep(50)
$rx = UartAvailable(0, 1)
print($rx)

if ($rx=1)
  $rxdata = UARTRead(0, 1, $rx)
  print( $rxdata )
endif

With this script, I am able to print $rxdata and then the rest of the script continues normally.

With Python


UART.InitHardwareUart(1, 115200) #have to have this to clear the buffer
sleep(1000)
UART.HardwareUartWrite(1,142) # Mode check 1
UART.HardwareUartWrite(1,35) # Mode check 2
sleep(50)
rxdata = 0
rx = UART.HardwareUartAvailable(1)
print(rx)

if rx == 1:
  rxdata = UART.HardwareUartRead(1,rx)
  print(rxdata)

With this script, i am unable to print rxdata and the console prints "Not connected" instead (and the script stop).

So, it seems that UART.HardwareUartRead does not behave like UARTRead (when UART.InitHardwareUart, UART.HardwareUartWrite and UART.HardwareUartAvailable behave as expected like their EZ-scripts equivalents).

Did I missed something ? Thanks

(By the way, the link to the Roomba manual page (https://synthiam.com/Software/Manual/Roomba-Movement-Panel-16116) does not seems to be active anymore)


Related Hardware Roomba

ARC Pro

Upgrade to ARC Pro

Experience early access to the latest features and updates. You'll have everything that is needed to unleash your robot's potential.

PRO
Synthiam
#1   — Edited

Add the iRobot Movement Panel skill and use that. It already reads data from the roomba for you and puts it in variables: https://synthiam.com/Products/Controls/Movement-Panels/iRobot-Roomba-Movement-Panel-19164

You're trying to use a byte array as a byte etc... The "UART.HardwareUartRead" returns a byte array. I wouldn't try to program and reinvent existing features in python AND try to learn python at the same time :)

Also, "Not Connected" means the ARC software is "not connected" to an EZ-B

#2   — Edited

Hi @DJ

Thank you for your feedback.

Quote:

I wouldn't try to program and reinvent existing features in python AND try to learn python at the same time
It is not indeed the EZ way :D, but I is what I have done with the EZ-scripts in the old days, and it is how I learned...

Quote:

You're trying to use a byte array as a byte etc... The "UART.HardwareUartRead" returns a byte array
I know that (I showed only a part of the code), but in my case it does not return anything else than "not connected"

What I don't understand is why is it working with EZ-Script and not with Python,... and only for the "Read" function. There is only one UARTRead command in EZ-Script and it works just fine. The UART.HardwareUartRead in Python is not supposed to do the same ?

Concerning the "Not connected" part, the issue is that ARC was in fact connected to an EZB v4 (everything else works) that's why I don't understand the error message...

#3   — Edited

OK, I have found where the "Not connected" issue come from.

UART.HardwareUartRead does not look at the same uartIndex.

The ROOMBA is connected to the UART port 1, but I have to define UartRead to 0 (UART.HardwareUartRead (0, x)), in Python or JS, for the command to work... That way, I obtain "ArrayByte" with

print(rxdata)

. Now I have to find what I must do with that xD...

PRO
USA
#4  

@fredebec: There is a small logic bug:

rx = UART.HardwareUartAvailable(1)
print(rx)

if rx == 1:
  rxdata = UART.HardwareUartRead(1,rx)
  print(rxdata)

I believe the UART.HardwareUartAvailable is analogous to EZ-script UARTAvailable:

Quote:

Receive the count of bytes available in the Peripheral UART Receive Buffer of the EZ-B v4. The UART receive buffers on the EZ-B v4 are 5,000 bytes. The Board Index is the EZ-B index starting at 0. The port can be 0, 1 or 2. Look near at the UART Port section lower in this document for the EZ-B Pin’s associated with each UART Port. Example: UARTAvailable(0, 0)
you are reading the number of bytes available in EZ controller can be 0-5000 and then your logic checks only runs if number is precisely 1... bear in mind, plain serial RX/TX without hardware error control, is prone to noise, so you need to prepare for other possibilities.

rx = UART.HardwareUartAvailable(1)
print(rx)

if rx > 0:
  rxdata = UART.HardwareUartRead(1,rx)
  print(rxdata)

your code is running on the PC not in the controller, so you have two round trips (HardwareUartAvailable, HardwareUartRead) to the controller, maybe you can reduce to one single roundtrip.

maybe something like this:

data = UART.HardwareUartReadAvailable(0)
if len(data)>0:
  print "no data"
else:
  print "do something"

a single round trip.

PRO
Synthiam
#5   — Edited

Also - he did find a bug in the ezb index being used as the uart index. I fixed it last night and releasing an update today

and if there’s noise on a uart line then someone’s got some pretty terrible wiring :)

#6  

@ptp

When using EZ-scripts, I never encounter any issue when looking at a precise number with UARTAvailable, so noise does not seems to be an issue. I have other scripts using other values, depending of the Roomba command (1, 2 or 3), so looking at the precise value is also some kind of check that the Roomba command is right...

I am going to try your simplified code, thanks for the tip.

@DJ, thanks a lot for having looked at my strange "not connected" behavior and for the update.

I still need to find why my Python script does not work as my EZ-scripts Maybe if i put the complete codes it will be more obvious what I try to achieve:

EZ-script:

uartinit(0, 1, 115200) #have to have this to clear the buffer
sleep(1000)
$RX_DATA=0
uartWrite(0,1,142) # Mode check
uartWrite(0,1,35) # Mode check
sleep(50)
$rx = UartAvailable(0, 1)

if ($rx=1)
  $RX_DATA = UARTRead(0, 1, $rx)
  $mode=GetByteAt($RX_DATA,0)
  if ($mode=0)
    print("OI is OFF")
  ELSEif ($mode=1)
    print("OI is in PASSIVE mode")
  ELSEif ($mode=2)
    print("OI is in SAFE mode")
  ELSEif ($mode=3)
    print("OI is in FULL mode")
  endif
ELSE
  print("OI is not responding")
endif

Python:

UART.InitHardwareUart(1, 115200) #have to have this to clear the buffer
sleep(1000)
UART.HardwareUartWrite(1,142) # Mode check 1
UART.HardwareUartWrite(1,35) # Mode check 2
sleep(50)
RX_DATA = 0
rx = UART.HardwareUartAvailable(1)

if rx == 1:
  RX_DATA = UART.HardwareUartRead(1,rx)
  mode = Utility.GetBit(RX_DATA,0)
  if mode == 0:
    print("OI is OFF")
  elif mode == 1:
    print("OI is in PASSIVE mode")
  elif mode == 2:
    print("OI is in SAFE mode")
  elif mode == 3:
    print("OI is in FULL mode")
else:
  print("OI is not responding")

It is the $RX_DATA = UARTRead(0, 1, $rx) and $mode=GetByteAt($RX_DATA,0) commands that I cannot make work in Python. But maybe it is still out of my league... :D

PRO
USA
#7   — Edited

Quote:

and if there’s noise on a uart line then someone’s got some pretty terrible wiring

Quote:

When using EZ-scripts, I never encounter any issue when looking at a precise number with UARTAvailable, so noise does not seems to be an issue.
I'm not saying the problem is noise, I'll quote something I've learned long ago:

Quote:

Dealing with uncertainty is one of the major problems in robotics and one of the main obstacles to populating the world with robots that do something useful.
in https://www.semanticscholar.org/paper/Modeling-Uncertainties-In-Robot-Motions-Timcenko-Allen/c1fab2b61dc33c4db945a690c74af68e2e2c4250

When I code, and specially, when i deal with sensor data, you need to be well prepared, that is the difference between blaming hardware, firmware and software most people forget that there are other variables e.g. QOS, Temperature, Humidity, Atmospheric pressure, cost/market : Automotive, Militar, DIY etc. It's a good practice, but, is not required.

I simplified your script to this:

import time

UART.InitHardwareUart(0, 115200)
time.sleep(1)

#discard any existing data
data = UART.HardwareUartReadAvailable(0)

UART.HardwareUartWrite(0,142) # Mode check 1
UART.HardwareUartWrite(0,35) # Mode check 2
time.sleep(.05)

data = UART.HardwareUartReadAvailable(0)
if len(data)>0:
  mode = data[0]
  if mode == 0:
    print("OI is OFF")
  elif mode == 1:
    print("OI is in PASSIVE mode")
  elif mode == 2:
    print("OI is in SAFE mode")
  elif mode == 3:
    print("OI is in FULL mode")
else:
  print("OI is not responding")


Please try and let me know if it works.

PRO
Synthiam
#8  

Can never be too careful:) I certainly did not mean to dismiss your input - always valued!

PRO
Synthiam
#9  

Upgrade to this: https://synthiam.com/Products/ARC/Releases/ARC-Beta-2020-05-08-00-19463

#10  

@DJ thanks for the update. No more "not connected message"

@ptp, thanks a lot for your help and advice

Your script does not work: here is the output of the console:

Start
> Array[Byte]((1))
> OI is not responding
Done (00:00:01.3940570)

Here the output with my ezscript (post #6):

Start
> 1
> []
> 1
> OI is in PASSIVE mode
Done (00:00:01.3808620) 
#11  

@ptp, update:

I succeeded in running your code, but only when keeping separated HardwareUartAvailable and HardwareUartRead as I used to do:

import time

UART.InitHardwareUart(1, 115200)
time.sleep(1)

#discard any existing data
rx = UART.HardwareUartReadAvailable(1)

UART.HardwareUartWrite(1,142) # Mode check 1
UART.HardwareUartWrite(1,35) # Mode check 2
time.sleep(.05)

data = 0
rx = UART.HardwareUartAvailable(1)
if rx > 0:
  data = UART.HardwareUartRead(1,rx)
  print(data)
  mode = data[0]
  if mode == 0:
    print("OI is OFF")
  elif mode == 1:
    print("OI is in PASSIVE mode")
  elif mode == 2:
    print("OI is in SAFE mode")
  elif mode == 3:
    print("OI is in FULL mode")
else:
  print("OI is not responding")

I obtain the expected output

Start
> Array[Byte]((1))
> OI is in PASSIVE mode
Done (00:00:01.3202339)

It seems the solution to my script was in the line

mode = data[0]

Could you explain what [0] means ?

Thanks

PRO
USA
#12  

data is an array, data[0] is the first byte, data[1] the second byte etc.

#13  

Oh, OK. It's clear now. Thanks

#14  

Thanks to your help and advice, I have successfully converted most of my Roomba data reading scripts.

I have looked a little closer to "arrays" and using the array module, I have improved the previous script. Indeed, when using 2 lines for UART.HardwareUartWrite(), I had inconstancy in the results. By using biteArray, it is now working every time.

here is my final script:

import time
import array

UART.InitHardwareUart(1, 115200)
time.sleep(1)

#discard any existing data
rx = UART.HardwareUartReadAvailable(1)

list = [142, 35]
arr = bytearray(list)
UART.HardwareUartWrite(1, arr)
time.sleep(.05)

data = 0
rx = UART.HardwareUartAvailable(1)
if rx > 0:
  data = UART.HardwareUartRead(1,rx)
  print(data)
  mode = data[0]
  if mode == 0:
    print("OI is OFF")
  elif mode == 1:
    print("OI is in PASSIVE mode")
  elif mode == 2:
    print("OI is in SAFE mode")
  elif mode == 3:
    print("OI is in FULL mode")
else:
  print("OI is not responding")
PRO
USA
#15   — Edited

Each call to HardwareUartWrite is a round-trip so there is a latency. Visualize the path: Python-ARC-Network-WIFI-EZB-Roomba you can imagine each step adding milliseconds. The roomba firmware must have timeout to avoid getting stuck waiting for a sub-command (second byte). I presume in some cases the sub-command (second byte) is handled as the the command and as consequence ignored. That is why is important to understand all the layers involved. Like DJ said does not make sense to reinvent the wheel. reinvention may be justified if you can learn from the process, later you will appreciate the software/control.

Padawan, you are in search of knowledge, Patient you must be. Your path you must decide. :)