Tag Archives: pi3hat

pi3hat C++ bindings update

The pi3hat repository, in addition to hosting a library for sending raw CAN frames using the pi3hat, has long had example source code demonstrating how to use that to communicate with a moteus controller. Recently however, C++ bindings were officially added to the primary moteus repository, that provide a more consistent, flexible and complete interface to moteus controllers. I’ve gone ahead and updated the pi3hat library to take advantage of that new interface, so now the pi3hat can be treated as just another transport like the fdcanusb.

First, I’ll show how to use the pi3hat in the most minimal way, then describe a bit of how it works and more advanced uses.

Usage

There are two easy ways to include the pi3hat into your project, copying the sources, or using cmake.

Copying sources

First, the full source code for the moteus C++ library and pi3hat transport are included in each binary distribution in the ‘YYYYMMDD-pi3hat_tools-*.tar.bz2’ file. For source access, all the distributions are equivalent. Inside that tarball the directory foo/bar has the set of examples from https://github.com/mjbots/moteus/tree/main/lib/cpp/examples along with the necessary pi3hat source files and a Makefile that can be used to compile all the examples on a Raspberry Pi. In this method, you can just copy all the source files from that distribution into your project and re-copy when you wish to update to a newer version.

cmake

The second method is to use cmake with FetchContent. This works best with cmake 3.24 or newer, but 3.10 or newer is permitted:

include(FetchContent)
FetchContent_Declare(
  pi3hat
  GIT_REPOSITORY https://github.com/mjbots/pi3hat.git
  GIT_TAG        00112233445566778899aabbccddeeff00112233
)

FetchContent_MakeAvailable(pi3hat)

add_executable(myproject myproject.cc)
target_link_libraries(myproject pi3hat::pi3hat)

Development

No matter how the library is incorporated, the API is basically the same. The only possible difference is that for cmake versions older than 3.24, or depending upon how you structure your build system, you may need to manually do:

#include "pi3hat_moteus_transport.h"

// ... near the beginning of main()
mjbots::pi3hat::Pi3HatMoteusFactory::Register();

After that, you can use the moteus C++ library in the exact same way as for the fdcanusb or other operating system level transports in simple cases. If you want to manually control pi3hat parameters, then the transport can be manually constructed, in a similar manner to that used in the python API:

using Transport = mjbots::pi3hat::Pi3HatMoteusTransport;
Transport::Options toptions;
toptions.can[4].slow_bitrate = 125000;
toptions.can[4].fdcan_frame = false;
toptions.can[4].bitrate_switch = false;
toptions.servo_map[1] = 1;  // ID 1 is on JC1
toptions.servo_map[2] = 2;  // ID 2 is on JC2
toptions.servo_map[3] = 2;  // ID 3 is on JC2
auto transport = std::make_shared<Transport>(toptions);

mjbots::moteus::Controller controller([&]() {
  mjbots::moteus::Controller::Options coptions;
  coptions.transport = transport;
  return coptions;
}());

In the above example, the pi3hat is configured with a fixed ID to bus mapping, and the CAN parameters for JC5 are set to be CAN 2.0 compatible.

Similarly, there exists a Cycle() overload of Pi3HatMoteusTransport that permits sending all the arguments that are available to Pi3Hat::Cycle, so you can use the moteus bindings, while still maintaining complete control over all the pi3hat specific features if you desire.

Conclusion

That’s all there is to it! No firmware updates are required for pi3hats or moteus controllers to use new API, you can just use the new API if you want to make your life easier!

pi3hat r4.5

I’m excited to announce a minor upgrade to the mjbots pi3hat product line, the pi3hat r4.5!

This has a few upgrades over the old r4.4b:

  • The input voltage range is expanded from 8-44V to 8-54V.
  • All CAN-FD ports have +-58V bus fault protection, up from +-12V.
  • 0.1″ pin headers are present for the Raspberry Pi I2C, UART, and for 3.3V and 5V outputs

Check it out at mjbots.com today!

pi3hat firmware and python release 2021-11-29

There’s an updated release out for the mjbots pi3hat which features a useful bug fix and a minor feature.

First, the configuration of automatic retransmission was broken in several ways. The symptoms for previous versions would be that any attempt to change the CAN configuration for a bus would result in all channels attached to that controller having auto-retransmit turned off. Since it was by default on, that would typically result in a decrease in transmission reliability, and in some particular cases with arbitration conflicts, could result in frequent packet loss. Fixing this requires updating both the firmware on the device and the C++ and python libraries. Fortunately, this would only come up if you were communicating with non-moteus devices using the pi3hat, which likely isn’t that common.

Upgrading the firmware of existing pi3hats is not trivial, since it requires use of the external stm32 programmer and an openocd version that is not yet packaged in any major Linux distribution.

Second, the python packages have been updated to support the newly released Raspberry Pi OS “bullseye” 11.0 out of the box.

CAN prefixes for moteus

The moteus controller, communicates exclusively over CAN-FD for command, telemetry, and diagnostics. It will accept either standard or extended frames, and until now, the ID format in terms of bits looked like the following:

33333222222221111111100000000
43210765432107654321076543210
XXXXXXXXXXXXXQSSSSSSSDDDDDDDD

Where:

  • X: Don’t care
  • Q: 1 for query, 0 for no query
  • S: source ID
  • D: destination ID

If the lower 8 bits matched the configured ID, all the X bits would be completely ignored and moteus would accept the CAN message as if it were destined for itself. This may not be super desirable, as it consumes nearly all of the available CAN-FD addressing space.

Starting with firmware version 2021-08-20, moteus now uses the following ID format:

33333222222221111111100000000
43210765432107654321076543210
PPPPPPPPPPPPPQSSSSSSSDDDDDDDD

Where P is a 13 bit “CAN prefix” that can be configured and defaults to 0. moteus will only accept CAN frames where this prefix matches the configured value*, and all frames it sends will have the prefix set as configured. This allows you to reclaim large sections of the CAN ID space for other devices in the event that moteus controllers share a bus.

[*] Footnote: The bootloader will require that the CAN prefix be set correctly, but WILL NOT set the prefix on the messages it sends. The existing moteus client side tools will function, but other devices on the bus may be confused.

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!

pi3hat configurable CAN

To date, the pi3hat CAN channels only supported CAN properties suitable for use with moteus controllers. Given that’s what most people are using them for, that’s fine. However, there was no real constraint behind that, just laziness.

Thus, I’ve released new firmware for the pi3hat that supports configuring the bitrate, FD-ness, and other properties of all 5 CAN channels.

Currently only the C++ library exposes the configuration functionality, but it will be easy enough to add to python when someone needs it.

pi3hat r4.4

It seems like all the posts I’m writing these days are for new products! Here’s the pi3hat r4.4:

There are two changes from the previous r4.2. First, it now supports voltage inputs up to 44V. Second, in support of future upgrades, the 5th CAN-FD port has been upgraded to support 8Mbps, but downgraded to no longer have a wide common mode voltage range.

THUS, IT IS NOT SAFE TO CONNECT THE CAN-FD PORT ON THE pi3hat r4.4 TO A power_dist r3.X BOARD.

Also, it is in stock at mjbots.com!

That said, the worldwide electronic supply chain is still in shambles. That combined with the Chinese New Year means that stock may be intermittent, and slight alternate versions to adjust to different parts may be forthcoming.