pimoroni / yukon

13 stars 5 forks source link

C++ Support #15

Open StooC opened 2 months ago

StooC commented 2 months ago

I understand that the Yukon uses a custom Micropython firmware but I've seen references to this firmware using C++ code to provide the interface that Micropython sits on top of. I've also seen it mentioned in a Tom's Hardware YouTube video about "it just being a RP2040 and so C++ used" like on any RP2040, my question is how feasible is this or if it's likely to be significantly more complex due to the custom hardware than just using a Pi Pico with a H-bridge etc?

In case it's relevant my use case for C++ is to integrate with ROS either via the "ros2_control" package where I wonder if MicroPython will be fast enough over UART (using a Proto module) or MicroROS which is C++ old. ROS2 would be running on a Pi 5 with a connected to the Yukon via UART.

ZodiusInfuser commented 2 months ago

Hi @StooC,

The driver parts of Yukon are written in C++ (motors, servos, onboard IO expanders), however the bulk of what makes Yukon work nicely (module detection, monitoring etc) comes from its Micropython library. We originally had full C++ support as a goal for the product, but the complexity of the library made that impractical for launch, and sadly not enough users have asked for it since then to make it rise up my priority list.

it just being a RP2040 and so C++ used" like on any RP2040, my question is how feasible is this or if it's likely to be significantly more complex due to the custom hardware than just using a Pi Pico with a H-bridge etc?

It's not that more complex from a hardware level. The key things Yukon has are two onboard IO expanders that are used to control the SLOW IO of each module, select which analog sensor to read, and enable the main power switch. The details of these can easily be gleamed from the Micropython library (or just ask me here or on the Yukon channel on the Pimoroni Discord).

The C++ implementation for the IO expanders can be found here: https://github.com/pimoroni/yukon/tree/main/firmware

I reckon it would be minimal work to modify a C++ program from Pico to Yukon to: Set the current limit on our Dual Motor driver, Turn on the main power, and PWM that module slot's 4 PWM outputs.

In case it's relevant my use case for C++ is to integrate with ROS either via the "ros2_control" package where I wonder if MicroPython will be fast enough over UART (using a Proto module) or MicroROS which is C++ old. ROS2 would be running on a Pi 5 with a connected to the Yukon via UART.

It's interesting you mention this use case. There was an entry in the recent PiWars that used a Yukon running Micropython, that they used as a ROS node, and communicated with over UART. They used a Quad Servo Direct Module to get access to the UART pins, but a Proto Module is equally viable. There blog is here: https://neave.engineering/2024/02/09/ne-five-upgraded-yukon-bet-on-it/

Perhaps you can reach out to them on Discord to find out more?

StooC commented 2 months ago

@ZodiusInfuser Thanks for coming back to me with a detailed reply.

Yes I can understand there would be less of a call for the C++ side compared to the MicroPython especially at initial launch, it's just a shame when comparing against products like the Motor 2040 which has C++ support but doesn't support 12v motors for example (max 10v).

It's not that more complex from a hardware level. The key things Yukon has are two onboard IO expanders that are used to control the SLOW IO of each module, select which analog sensor to read, and enable the main power switch. The details of these can easily be gleamed from the Micropython library (or just ask me here or on the Yukon channel on the Pimoroni Discord).

Thanks for pointing out the firmware, I've had a quick look through and I can see some of the details like the TCA9955 handling but I would need to dig in deeper and see what I could get to work to learn more I think. However I am concerned I can break the hardware with C++ in way I can't do using the custom MicroPython as the firmware is designed to check for and prevent such mistakes?

For example if I was to upload this Pico button example I assume the button & LED will work (if the GPIO's are right) but would I damage anything else as the expected initialization code isn't present? You also mention about enabling the main power switch so I assume I would need to do that to use even simple modules like the proto module?

It's interesting you mention this use case. There was an entry in the recent PiWars that used a Yukon running Micropython, that they used as a ROS node, and communicated with over UART. They used a Quad Servo Direct Module to get access to the UART pins, but a Proto Module is equally viable. There blog is here: https://neave.engineering/2024/02/09/ne-five-upgraded-yukon-bet-on-it/

I've seen the NeFive and noticed they had upgraded to the Pi 5 but I somehow missed that they had also used the Yukon, looking at their source they do mention about using the Servo Direct module for UART but I can't see how that module exposes the UART from the pinout of the module but clearly they got it to work! My best guess is they have reconfigured the RP2040 IO pints (i.e. fast IO 1-4) looking at the picture but I would probably use a proto module.

They don't seem to have a Discord link on their site (although they have many others) do you know it? I have tried their Facebook instead but possibly not the best place for a discussion on it.

I have one more question but otherwise happy for you to close this issue. If I was to flash my own uf2 (i.e. a C++ build), does this change how I would apply the original Yukon firmware or is it no different to flashing any Pi Pico?

ZodiusInfuser commented 2 months ago

Yes I can understand there would be less of a call for the C++ side compared to the MicroPython especially at initial launch, it's just a shame when comparing against products like the Motor 2040 which has C++ support but doesn't support 12v motors for example (max 10v).

Motor 2040 doesn't have that much in the way of C++ support. There's the pin definitions: https://github.com/pimoroni/pimoroni-pico/blob/main/libraries/motor2040/motor2040.hpp Then the rest of it is the Motor, MotorCluster, and Encoder classes. All these are usable by Yukon.

I suppose Yukon could benefit from a pin definitions file too 🤔

Thanks for pointing out the firmware, I've had a quick look through and I can see some of the details like the TCA9955 handling but I would need to dig in deeper and see what I could get to work to learn more I think. However I am concerned I can break the hardware with C++ in way I can't do using the custom MicroPython as the firmware is designed to check for and prevent such mistakes?

The main thing the firmware does is initialise the TCA9555 expanders into a known state on boot-up and reset. This can be easily copied into any standalone C++ program. The Yukon library introduces all the other protections, but someone could easily write a micropython program that did not use the library, putting them in the same position as a C++ user. That means they won't have the autodetection of modules, so in theory could incorrectly drive a DC motor as a servo or speaker, and thus damage it if it drove unexpectedly and hit something.

You also loose out on the monitoring, which would let you set soft limits for voltage, current, and temperature. There will always remain hard limits for voltage and current, thanks to the onboard e-Fuse, and most heat producing modules have their own thermal cutouts somewhere above 100 degrees C.

For example if I was to upload this Pico button example I assume the button & LED will work (if the GPIO's are right) but would I damage anything else as the expected initialization code isn't present?

You would not immediately damage anything by running that code. From a fresh power up Yukon will be in a default state, which includes the main output being disabled.

The LED and button would not work, as the ones on Yukon are wired off the IO expanders. You could easily wire an LED and button to a proto module though and get that to work without any Yukon specific code.

You also mention about enabling the main power switch so I assume I would need to do that to use even simple modules like the proto module?

Only the V+ line of the proto module would be affected by the main power switch. All the other IO are usable without it enabled. So having UART comms active from a proto module, whilst having motors unpowered is entirely possible.

I've seen the NeFive and noticed they had upgraded to the Pi 5 but I somehow missed that they had also used the Yukon, looking at their source they do mention about using the Servo Direct module for UART but I can't see how that module exposes the UART from the pinout of the module but clearly they got it to work! My best guess is they have reconfigured the RP2040 IO pints (i.e. fast IO 1-4) looking at the picture but I would probably use a proto module.

That is correct. They have looked at the Yukon pinout for the slot they intend to use, seen what each Fast IO's GP number is, and what its pins are capable of: https://cdn.shopify.com/s/files/1/0174/1800/files/yukon_pinout_diagram.png

They don't seem to have a Discord link on their site (although they have many others) do you know it? I have tried their Facebook instead but possibly not the best place for a discussion on it.

They go as @keegan.neave on Discord. They are also a member of the Yukon channel if you wish to tag them.

I have one more question but otherwise happy for you to close this issue. If I was to flash my own uf2 (i.e. a C++ build), does this change how I would apply the original Yukon firmware or is it no different to flashing any Pi Pico?

Nope. Just put the board back into boot mode and copy over the Yukon micropython build. Depending on your C++ program size, you may find that the files on your Yukon have been overwritten, in which case copy them back. Or flash the board with the .uf2 that includes both Micropython and the libraries.

StooC commented 1 month ago

Looking at the link on the Motor2040 store page, does seem to link to a good amount of examples (https://github.com/pimoroni/pimoroni-pico/tree/main/examples/motor2040). It have not looked into these in detail but checking a couple it does just seem to be the pin definitions as the only "library" included so there isn't as much of a library provided as I assumed.

However even the pin definitions and some simple examples would help provide a base to build on, even if it has to be made clear that the "safety is off" and you are missing out of some of the extras the firmware provides. Having said that perhaps over time the community could contribute more examples built upon this base with features like voltage and temperature monitoring.

If pin definitions and some basic examples were created then perhaps creation of a "yukon-cpp" repository would help keep it separate and the readme could detail what so of the limitations etc.

While I can't promise (life has a habit of getting in the way) I'll see if I could put together the most basic of "hello world" examples at the weekend to see how difficult it would be.