Package: rsl-comm-py
RSL Comm Python DriverTL;DR:"Swiss army knife"for using
theUM7,UM8,
andshearwaterorientation sensors with Python 3
(Python 3.7+, including Python 3.10).UM7originally came with the"Serial Software Interface"for handling / communicating with the sensor, which is currently available for Windows only.Thepython3driver provided here is designed to keep you up and running
on different platforms (Linux, Windows, Mac).
If you have theUM7,UM8, orshearwaterboard and want to use it on Linux
(e.g. Ubuntu, Debian, Raspbian, Yocto, Suse, etc.),
Windows, or Mac, this repo provides driver code to send / receive individual packets
and receive broadcasts, as well example code how to create a sensor communication object.The driver has the following capabilities:read / write single registers to/fromUM7,UM8,shearwateroverSPI;read / write single registers to/fromUM7,UM8,shearwateroverUART;receive broadcast packets from theUM7,UM8,shearwatersensor overUART;register map and interpretation of the sensor registers forUM7,UM8,shearwater.Checking out the repo with submodules:This repo containsgit submodules,
in particularlyrsl_xml_svdproject is included as a submodule. In order to check out the project, including
submodules use the following command:gitclone--recurse-submodulesgit@github.com:RedshiftLabsPtyLtd/rsl_comm_py.gitIf the repo is already cloned without submodules, then in the existing repo:gitsubmoduleupdate--recursive--initIf using GUI client like git kraken, the followingpostmight be useful.After syncing the sub-modules, thersl_xml_svdfolder
should appear inside the repo, pointing exactly to the commit specified in this repository.Repository structureTo get started, you need to know that communication with theUM7,UM8, andshearwateris organized as follows. For each sensor, there is a file with register description, and
separate files with UART and SPI communication. The register description code interprets the
received payload, and sensor files handle constructing, transmitting and receiving packets.E.g. for the UM7 the UART communication is coded inum7_serial.pyfile,
where theUM7Serialclass is defined.
Information about UM7 registers comes toum7_serial.pyfrom theum7_registers.pyfile, where
the accessing to the UM7 registers are stored.
Since it is possible to access the UM7 register map over UART and SPI,
the register data (e.g. addresses, fields, and their meaning) is stored in a separate file.
In theexamplesfolder we store the examples how to communicate with the
sensor.TheUM7,UM8, andshearwaterregister descriptions are stored in SVD files,
(um7.svd,um8.svd,shearwater.svd)
and is parsed by thersl_svd_parser.py.
The parser extracts the information from the XML file and fills in python data classes.Below we outline the repo structure:rsl_comm_py: top-level python package;rsl_comm_py/examplespackage with example code for receiving broadcast / reading / writingUM7,UM8orshearwaterregisters;rsl_comm_py/rsl_xml_svdpackage storesUM7,UM8, andshearwaterregisters data in SVD (orSystemViewDescription) format and parsing code. For content description of the package, look at therepo;rsl_comm_py/testpytesttests for register map code generation;rsl_comm_py/rsl_generate_shearwater.py: invokepythonandC/C++code generation forshearwaterand save generated results;rsl_comm_py/rsl_generate_um7.py: invoke code generation forUM7and save generated results;rsl_comm_py/rsl_generator.py: code generation forum7_registers.pyandshearwater_registers.pyfrom the SVD file;rsl_comm_py/rsl_spi.py: generic SPI driver classes forUSB-ISSor SPI-bus (Linux);rsl_comm_py/serve_rsl_autodetect.py: copies thersl_autodetect.pyscript to the desired location;rsl_comm_py/rsl_autodetect.py: a script for saving configuration for connection to theUSB Expansion Board;rsl_comm_py/shearwater_broadcast_packets.py:dataclassesforshearwaterbroadcast messages;rsl_comm_py/shearwater_registers.py:shearwaterregister description file;rsl_comm_py/shearwater_serial.py:shearwaterUART driver;rsl_comm_py/shearwater_spi.py:shearwaterSPI driver forUSB-ISSor SPI-bus (Linux);rsl_comm_py/um7_broadcast_packets.py:dataclassesforUM7broadcast messages;rsl_comm_py/um7_registers.py:UM7register description file;rsl_comm_py/um7_serial.py:UM7UART driver;rsl_comm_py/um7_spi.py:UM7SPI driver forUSB-ISSor SPI-bus (Linux);HW PrerequisitesUM7,UM8,shearwaterboards provide serial (UART) and SPI interfaces, hence the two main ways to access the sensor data
are UART (serial) or SPI. The differences in short: UART provides broadcast functionality, i.e.
when packets can transmitted by the board with a specified frequency (transmission frequencies are set up in
configuration registers), and it is possible to issue sensor commands (i.e. accessing command registers).
SPI access the sensor register on demand (i.e. no broadcast functionality), and only
configuration and data registers can be accessed. Accessing commands is only supported
over UART.Serial connection (UART)When usingUM7,UM8,shearwaterover serial, it is possible to connect to the target system (i.e. user's target):to the serial port directly (e.g. when serial pins are wired out as on theRaspberry PI,NVIDIA Jetson Nano,
or other board computers with GPIO and UART pins wired out);to the USB port using theUSB Expansion Board,
which performs USB to serial conversion.SPI connectionWhen using theUM7,UM8,shearwaterover SPI, there are also a couple of possibilities:to the SPI pins directly (e.g. Raspberry PI, NVIDIA Jetson Nano), i.e.
the pins are wired to theSoCdirectly;to the USB port using USB to SPI converter, e.g.USB-ISS.The difference between the two, that in the first case SoC pins support the SPI
directly (on the hardware level, which also mirrors in the OS level), then the OS is likely to have the SPI device
driver built-in (e.g. Raspberry PI). In the second case, using external converter (e.g. USB-ISS),
the device will be shown as a so-calledcdc_acm(communication device class),
and low-level SPI communication will be done by the converter, yet to the OS the
converter will be shown as Abstract Control Model (ACM) USB Device.Installationpipinstallrsl-comm-pyPython dependenciesTL;DR:install (i)pyserial,jinja2.If you want to use SPI: if using on Linux and use SPI bus directly, installspidev,
otherwise if using USB-ISS installusb_isspython package.Alternatively, one may useenvironment.ymlto create conda environment with dependencies resolved.If you are usingpython3.6, you need to installdataclasses(the module is included in standard library sincepython3.7,
and for3.6needs to be installed separately).Python driver 101The python driver for Redshift Labs Pty Ltd orientation sensors works as follows:
the*.svd(e.g.um7.svd) file describes the register map, and the fields of registers.
From the*.svdfile the[sensor]_registers.py(e.g.um7_registers.pyorshearwater_registers.py) is generated.
The files have generated methods for reading / writing single registers,
and how to interpret the payload. In addition, the files
(e.g.um7_registers.pyorshearwater_registers.py) provide
abstract methodsconnect,read_register, andwrite_register.The[sensor]_serial.pyfiles (e.g.shearwater_serial.pyorum7_serial.py)
implement required functionality to read / write registers via the UART interface.
In addition to this the[sensor]_serial.pyfiles also implement decoding of broadcast packets.
Connection to the UART might be done viaUSB Expansion Boardand for this the so-calleddevicefile might be used.
One can also connect to the port directly using theportargument.The[sensor]_spi.pyfiles (e.g.shearwater_spi.pyorum7_spi.py)
implement required functionality to read / write registers via SPI interface.
In particularly two ways of connecting to SPI are supported:
either usingUSB-ISSadapter, and correspondingusb_isslibrary, or
connecting to the SPI port directly, e.g. if Linux kernel have SPI functionality
activated, and the SPI interface is wired directly to the SoC (e.g. as for Raspberry PI).
This way the communication is done using thespidevpython library.OS PrerequisitesWhen plugged in on a Linux system,
theUM7,shearwater,UM8sensor should appear
as/dev/ttyUSB*device
(this is only true when you are usingUSB Expansion Boardwhich in turn uses USB-to-serialFTDIchip.If you are on a Linux machine, your Linux user must be a member of thedialoutgroup
(e.g. see thisthread)
to be able to read/writettyUSB*devices
without root privileges.Device autodetectTo facilitate discoveringRSLsensors
(UM7,UM8,shearwater) among other
USB-to-serial devices (and store the configuration when
re-plugging and/or adding other devices), we providersl_autodetectmethod
and thersl_autodetect.pyscript (both are equivalent).These methods creatersl_[SERIAL_NUM].jsonconfiguration file,
which is then used to match the USB-to-serial converter to which
the sensor is connected.Usingrsl_autodetectmethodLaunchrsl_autodetectmethod:fromrsl_comm_pyimportrsl_autodetectrsl_autodetect()At this point, thersl_[SERIAL_NUM].jsonfiles is created
in the current directory.Usingrsl_autodetect.pyscriptObtain thersl_autodetect.pyscript fromrsl_comm_pypackage:fromrsl_comm_pyimportserve_autodetect_scriptserve_autodetect_script()Launch the script and follow instructions:./rsl_autodetect.py--helpAt this point, thersl_[SERIAL_NUM].jsonfile is created
in the current directory.Important:The createdrsl_[SERIAL_NUM].jsonconfiguration file
should be used as a device file, when creating instance ofUM7Communicationclass:fromrsl_comm_pyimportShearWaterSerialshearwater_sensor=ShearWaterSerial(device='rsl_[MY_SERIAL_NUM].json')Quick start forUM7CreateUM7serial communication object, UM7 connected to a port/dev/ttyUSB0,
and read the firmware version:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')print(f"um7 firmware revision:{um7_serial.get_fw_revision}")Readingall typesof broadcast packets fromUM7, 1000 packets in total:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')forpacketinum7_serial.recv_broadcast(num_packets=1000):print(f"packet:{packet}")Reading theraw sensor databroadcast packets fromUM7, not limiting number of packets:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')forpacketinum7_serial.recv_all_raw_broadcast():print(f"packet:{packet}")Reading 100processed sensor databroadcast packets fromUM7:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')forpacketinum7_serial.recv_all_proc_broadcast(num_packets=100):print(f"packet:{packet}")Reading theEuler anglesbroadcast packets fromUM7:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')forpacketinum7_serial.recv_euler_broadcast():print(f"packet:{packet}")Reading theCREG_COM_SETTINGSconfiguration register fromUM7:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')print(f"received value:{um7_serial.creg_com_settings}")Writing 40 (changingALL_RAW_RATEto 40 Hz) to theCREG_COM_RATES2register:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')um7_serial.creg_com_rates2=40Quick start forshearwaterReadshearwaterfirmware build id:fromrsl_comm_pyimportShearWaterSerialshearwater=ShearWaterSerial(device='rsl_A500CNHH.json')print(f"get_fw_build_id :{shearwater.get_fw_build_id}")CreateUM7serial communication object, UM7 connected to a port/dev/ttyUSB0,
and read the firmware version:fromrsl_comm_pyimportShearWaterSerialshearwater=ShearWaterSerial(port_name='/dev/ttyUSB0')print(f"shearwater firmware revision:{shearwater.get_fw_build_version}")Slow startTake a look at the availableexamples.In order to use thepythondriver functionality one first needs to
create a communication object (e.g.UM7Serial,UM7SpiLinuxPort,
orShearWaterSerial,ShearWaterSpiUsbIss).The construction of the UART communication object can be done
either by specifying aport_namedirectly (e.g./dev/ttyS0), or
by specifying thedevicefile that storesUSB2Serialconfig
(e.g.rsl_A500CNP8.json). Thedeviceargument shall
only be used, when RSL board (UM7,UM8,shearwater) is connected via theUSB Expansion Board,
thedevicestores properties of the expansion board. Why?
The issue to keep in mind that when the sensor is re-plugged,
it might appear to the OS as different serial connection,
i.e. when first plugged in the OS detects the device as/dev/ttyS0, then after re-plugging exactly the same
sensor might appear by different port name, e.g./dev/ttyS1, which
means the user code needs to be changed.
If using thedevice, we store properties of theUSB Expansion Boardin a JSON file (e.g. converter chip ID)
and search connection which match with the properties, and
in this case connecting to the sensor, even if is shown as a
different serial connection by the OS.So the communication object can either be created with specifying theport_name:fromrsl_comm_pyimportUM7Serialum7_serial=UM7Serial(port_name='/dev/ttyUSB0')Or with specifying thedevice:fromrsl_comm_pyimportUM7Serialum7=UM7Serial(device='um7_A500CNP8.json')The two options are exclusive, i.e. specifying bothport_nameanddevicewill not work.Accessing to the individual registers is done via pythonproperties.
Properties for register names are all lower-case, split by_.For example, reading theCREG_COM_RATES1:fromrsl_comm_pyimportUM7Serialum7=UM7Serial(device='rsl_A500CNP8.json')um7.creg_com_rates1Note, that reading single register is quite a slow operation,
since one first constructs and sends a packet, and then parses
output for response.
Reading single registers is not recommended for reading sensor data,
since it might happen, that data from different sensor registers come from different measurements.
We strongly advice to use broadcast messages for reading sensor and fusion data.UM7 Data PacketsUM7sends different types of broadcast messages over the UART.
These messages are e.g.HEALTHpacket (i.e. theDREG_HEALTHregister),
raw sensor data (raw gyro, accelerometer, and magnetometer, and temperature),
processed sensor data (processed gyro, accelerometer, and magnetometer),
Euler angles, quaternions.These data packets are stored in the repo asdataclassesin the fileum7_broadcast_packets.py.
Note, that only payload stored in the dataclasses, and all the
checks (e.g. checksum, data length) is done during broadcast reception.For example, the raw data broadcast message has the following payload:fromdataclassesimportdataclass@dataclassclassUM7AllRawPacket:gyro_raw_x:intgyro_raw_y:intgyro_raw_z:intgyro_raw_time:floataccel_raw_x:intaccel_raw_y:intaccel_raw_z:intaccel_raw_time:floatmag_raw_x:intmag_raw_y:intmag_raw_z:intmag_raw_time:floattemperature:floattemperature_time:floatshearwaterData Packetsshearwater, similar toUM7sends broadcast messages over the UART.
These are e.g. raw sensor data (raw gyro, accelerometer, and magnetometer, and temperature),
processed sensor data (processed gyro, accelerometer, and magnetometer),
Euler angles, quaternions.These data packets are defined in
in the fileshearwater_broadcast_packets.py.For example, the data broadcast message with the processed sensor data
has the following payload:fromdataclassesimportdataclass@dataclassclassShearWaterAllProcPacket:gyro_1_proc_x:floatgyro_1_proc_y:floatgyro_1_proc_z:floatgyro_1_proc_time:floatgyro_2_proc_x:floatgyro_2_proc_y:floatgyro_2_proc_z:floatgyro_2_proc_time:floataccel_1_proc_x:floataccel_1_proc_y:floataccel_1_proc_z:floataccel_1_proc_time:floatmag_1_proc_x:floatmag_1_proc_y:floatmag_1_proc_z:floatmag_1_norm:floatmag_1_proc_time:floatmag_2_proc_x:floatmag_2_proc_y:floatmag_2_proc_z:floatmag_2_norm:floatmag_2_proc_time:floatAcknowledgementWe are so grateful for the open source community for creating
open source UM7 driver versions and sharing it with a world!
We are inspired by your work, and at the same time
want to improve:
provide UART and SPI communication, in detail documentation
and explanations to facilitate the start for new users.The acknowledgments go to:Daniel Kurekand hisum7repository,
for implementing the first driver for interfacing with UM7;Till Buschand hisum7fork of Daniel's Kurek repo, for extending on the Daniel's work and
adding new functionality.MaintainerDr. Konstantin Selyunin, for
suggestions / questions / comments please contact: selyunin [dot] k [dot] v [at] gmail [dot] com