uart.read() error with PYBD-SF6W

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
kbrenner
Posts: 5
Joined: Mon Jan 20, 2020 8:05 pm

uart.read() error with PYBD-SF6W

Post by kbrenner » Mon Jan 20, 2020 10:19 pm

I am using the PYBD-SF6W to control the output of a Dynamixel motor (http://www.robotis.us/dynamixel-xm430-w210-r/) that utilized UART communication. I have a shield for my Pyboard that has an RS485 transceiver (https://www.digikey.com/product-detail/ ... ND/1805638) and all connections with the Pyboard (VCC, GND, A, B, etc.) have been confirmed to be working.

The code that I had written to control the device was first used with a PYBv1.1, and the UART communication worked perfectly with communicating with the motor. However, it only worked with v1.10 and below (v1.11 and above caused errors as well). I then transferred over to the PYBD-SF6W, which is currently on v1.12-35-g10709846f and the same types of errors are occurring again. I have a feeling that something was updated in the UART class between versions (and possibly between boards). I have obviously ensured that the correct wiring and pinout calling has been done in the transfer from PYBv1.1 to PYBD-SF6W since the layout is obviously different. The issue lies in the firmware. Here is the code that I am trying to run (and have been successful with on v1.10 on the PYBv1.1):

import pyb
from pyb import Pin
from pyb import UART
import binascii
import crc_calc

headerString = "fffffd00"
motorID = "01"
initTorque = "060003400001"

# Setup pyboard and UART communication
wrist_pin_out = Pin('X2', Pin.OUT_PP)
uart = UART(1, 1000000)

# Write a command message to a motor to enable it
wrist_pin_out.high()
pyb.udelay(1000)
commandV = headerString + motorID + initTorque
finalS = createCommandString(commandV)
uart.write(finalS)

# Read the response from the motor
wrist_pin_out.low()
tmp = uart.read(11) # read up to 5 byte
print(tmp)


I have left out the createCommandString function since it is unnecessary for this debugging (basically, it just converts to hex and adds some CRC). I've left it out since I have confirmed that the variable "finalS" is identical between firmwares/devices. The output of tmp = uart.read(11) is different between the two. When it worked on the PYBv1.1 it returned:

b'\xff\xff\xfd\x00\x01\x04\x00U\x00\xa1\x0c'

This same output on the PYBD-SF6W is simply "None", which indicates a timeout. I was hoping someone might be able to help me understand what is happening with UART.read() in between the two devices/firmwares. Thanks!
Last edited by kbrenner on Tue Jan 21, 2020 3:31 pm, edited 1 time in total.

User avatar
pythoncoder
Posts: 4023
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: uart.read() error with PYBD-SF6W

Post by pythoncoder » Tue Jan 21, 2020 9:17 am

By far the best way to debug this would be to put a scope or logic analyser on the UART lines. A Saleae analyser (or Chinese clone) will show exactly what's going on. A few thoughts on tests you might perform.

The baudrate of 1000000 is not a standard value. I would check whether the UART is actually delivering that rate, or change to a standard value. 115200 is widely used.

Does the motor behave as if it is receiving data?

Lastly I'd try reading back character by character in a loop to see what (if anything) is coming back.
Peter Hinch

kbrenner
Posts: 5
Joined: Mon Jan 20, 2020 8:05 pm

Re: uart.read() error with PYBD-SF6W

Post by kbrenner » Tue Jan 21, 2020 7:12 pm

pythoncoder wrote:
Tue Jan 21, 2020 9:17 am
By far the best way to debug this would be to put a scope or logic analyser on the UART lines. A Saleae analyser (or Chinese clone) will show exactly what's going on. A few thoughts on tests you might perform.

The baudrate of 1000000 is not a standard value. I would check whether the UART is actually delivering that rate, or change to a standard value. 115200 is widely used.

Does the motor behave as if it is receiving data?

Lastly I'd try reading back character by character in a loop to see what (if anything) is coming back.
Hi Peter, thanks for the response. I do not currently have access to a logic analyzer. I am using that baud rate since that is the baud rate that is accepted by the Dynamixel motor (and I haven't had any issues with that baud rate on the PYBv1.1). I have confirmed that with both scenarios (PYBv1.1 on Micropython version 1.10 from January 25th, 2019 and PYBDvSF6W on Micropython version 1.12-35-g10709846f from December 31st, 2019), the same UART message is being written, and in both cases, uart.write(finalS) returns 13 (if it wasn't sending, I would expect None for timeout).

Now that I think about it, the problem is most likely with uart.write(finalS) because uart.read(11) is just being stored as a variable to confirm that something was read and not actually called. I am not sure what you mean by reading back character by character. Which characters are you referring to?

I am curious if there are any changes between UART between these two versions of Micropython or two devices (PYBv1.1 and PYBDvSF6W) that may be causing this issue. Seeing as though neither the code nor the hardware of the motors has changed, I am guessing that it is something with the firmware on the pyboards. I say that because I am consistently returning None or b'\x00' upon calling uart.read().

I am also relatively novice at Micropython (as this is my first project) so I may need certain mundane solutions explained in more detail. Thank you in advance!

User avatar
dhylands
Posts: 3300
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: uart.read() error with PYBD-SF6W

Post by dhylands » Tue Jan 21, 2020 7:48 pm

I've also got code for controlling the Dynamixels (AX-12). In my case, I don't use any external hardware. The code puts the UART in half-duplex mode (which connects Tx to Rx internally) and disable the receiver while transmitting so I don't receive my own transmissions: https://github.com/dhylands/bioloid3/bl ... rt_port.py

I've only tested this on the pyboard 1.1 (STM32F4xx) and not the newer boards though.

I'm not aware of any issues with the STM32 using 1 Mbit.

User avatar
dhylands
Posts: 3300
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: uart.read() error with PYBD-SF6W

Post by dhylands » Tue Jan 21, 2020 7:57 pm

Also, the PYBD is quite a bit faster than the pyboard 1.1, so if you call uart.read before the data has actually arrived back from the servo, then you'll get None, because the data just isn't there yet.

My code polls in the main loop for characters from the UART, and then feeds each character to a packet parser (the process_byte function found in this file: https://github.com/dhylands/bioloid3/bl ... /packet.py) process_byte uses a statemachine to build up the packet and once a complete packet is received, it will be returned.

This code shows my typical main loop: https://github.com/dhylands/bioloid3/bl ... er.py#L136 That code was running on a Espruino Pico which was basically acting as a USB Dynamixel interface for a PC. It would receive packets over the USB serial and then forward them out over the HW UART, and vica-versa.

uCTRL
Posts: 39
Joined: Fri Oct 12, 2018 11:50 pm

Re: uart.read() error with PYBD-SF6W

Post by uCTRL » Tue Jan 21, 2020 10:06 pm

Also, the PYBD is quite a bit faster than the pyboard 1.1, so if you call uart.read before the data has actually arrived back from the servo, then you'll get None, because the data just isn't there yet.
Is it really that hard for developers to implement a callback functionality for UART, both Rx and TX would be useful?
Would make programming and efficiency so much better.

Python is promoted as "Easy" to use language.

This has come up so many times and is just ridiculous to be ignored.

User avatar
pythoncoder
Posts: 4023
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: uart.read() error with PYBD-SF6W

Post by pythoncoder » Wed Jan 22, 2020 9:57 am

uCTRL wrote:
Tue Jan 21, 2020 10:06 pm
...Is it really that hard for developers to implement a callback functionality for UART, both Rx and TX would be useful?...
The benefit of callbacks is to facilitate concurrency. MicroPython achieves this with uasyncio. The following code sample handles concurrent reading from and writing to a UART. Link X1 and X2 on a Pyboard to test:

Code: Select all

import uasyncio as asyncio
from pyb import UART
uart = UART(4, 9600)

async def sender():
    swriter = asyncio.StreamWriter(uart, {})
    while True:
        await swriter.awrite('Hello uart\n')
        await asyncio.sleep(2)

async def receiver():
    sreader = asyncio.StreamReader(uart)
    while True:
        res = await sreader.readline()
        print('Recieved', res)

loop = asyncio.get_event_loop()
loop.create_task(sender())
loop.create_task(receiver())
loop.run_forever()
@kbrenner Debugging by reading one character at a time:

Code: Select all

while True:
   while not uart.any():
       pass
   print(hex(uart.readchar()))
This will wait forever for data but will give you an indication of what is being received and when.
Peter Hinch

Post Reply