pi3hat python raw CAN-FD

The pi3hat, among other things has 5 CAN-FD ports. You can use them to drive a lot of moteus servos, but they are perfectly fine CAN-FD ports generally. The C++ library has always been able to send and receive arbitrary frames (and recently at arbitrary bitrates), but the python interface was lacking, only exposing a portion of this functionality.

As of version 0.3.11, the python library (pip3 install moteus-pi3hat) now exposes everything you need to be able to send and receive arbitrary CAN frames from any of the ports, as well as configure all the timing options for waiting for responses from slave devices.

This is what a sample usage of raw frames, mixed in with moteus frames, looks like:

# To send a raw CAN, you must manually instantiate a
# 'moteus.Command' and fill in its fields, along with which
# bus to send it on.
raw_message = moteus.Command()
raw_message.raw = True
raw_message.arbitration_id = 0x0405
raw_message.bus = 5
raw_message.data = b'1234'
raw_message.reply_required = False

# A single 'transport.cycle' call's message list can contain a
# mix of "raw" frames and those generated from
# 'moteus.Controller'.
#
# If you want to listen on a CAN bus without having sent a
# command with 'reply_required' set, you can use the
# 'force_can_check' optional parameter.  It is a 1-indexed
# bitfield listing which additional CAN buses should be
# listened to.

results = await transport.cycle([
       raw_message,
       controller.make_query(),
   ], force_can_check = (1 << 5))

# If any raw CAN frames are present, the result list will be a
# mix of moteus.Result elements and can.Message elements.
# They each have the 'bus', 'arbitration_id', and 'data'
# fields.
#
# moteus.Result elements additionally have an 'id' field which
# is the moteus servo ID and a 'values' field which reports
# the decoded response.
for result in results:
    if hasattr(result, 'id'):
        # This is a moteus structure.
        print(f"{time.time():.3f} MOTEUS {result}")
    else:
        # This is a raw structure.
        print(f"{time.time():.3f} BUS {result.bus}  " +
              f"ID {result.arbitration_id:x}  DATA {result.data.hex()}")

It isn’t the cleanest API, but it does get the job done!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s