I am controlling an ODrive through CAN from a RPI.
How can I also include the current measurements from the two axes in the messages which are automatically sent by ODrive?
I know that the already available 0x014 message does that on request, but I would rather have it directly send those values (like it is for the axis position and velocity).
Basically, I’d like to add two more messages (one for each axis) containing the i_q and the i_d measured on each axis (or maybe only a message with the i_q components of both axis).
To my understanding, this requires modifying the current firmware on the ODrive and flashing it on the board.
Can someone give me an indication on where exactly should I look to modify the firmware code and also on the procedure/hardware needed for flashing the modified firmware?
Thanks in advance for the help
So first off, download the firmware and check that you can build and flash it:
(basically, follow ODrive Firmware Developer Guide | ODrive but the basic steps are below)
sudo apt install git git-lfs make tup gcc-arm-none-eabi gdb-multiarch openocd python3-yaml python3-jinja2 python3-jsonschema libboost-dev git clone git://github.com/odriverobotics/ODrive.git cd ODrive pip3 install -r tools/requirements.txt cd Firmware cp tup.config.default tup.config nano tup.config # edit settings to suit your board tup
If that worked, then take a look at
Find the function
CANSimple::get_encoder_estimates_callback(const Axis& axis) and make a copy that does what you want.
Then look at
CANSimple::service_stack() and add your function where get_encoder_estimates_callback is called.
You could also edit odrive_interface.yaml and add a new property to
ODrive.Axis.CanConfig so that you can change the rate at which your new messages are sent.
Then once you’ve got your code to compile, you can flash with:
python3 tools/odrivetool dfu Firmware/build/ODriveFirmware.hex
Thanks @towen, that is exactly what I needed.
@towen I have successfully modified the firmware and build it without errors (I still have to flash it and test it).
However, there is a practical question/problem which came to my mind.
I will use the modified firmware to obtain the full axis state with a predefined rate.
There will also be a high level controller sending axis commands (in particular torque) to both axes, based on the full robot state coming from both the axes and the onboard IMU (the IMU is connected to my RPI on via an independent CAN bus).
Now, supposing I just got the full state measurements and computed the control inputs, I will send two messages with base ID 0x00E to command the motor torques.
However, how can I be sure that I am sending those commands at a more or less reliable rate if their ID will make those message lower priority ones with respect to the Heartbeat, etc… messages?
I was thinking of changing the IDs of the command messages (torque included), so that they will have higher priority than the Heartbeat and axis state feedback. But this is probably only partially effective since, due to the fact that
can_id = axis_id << 5 | cmd_id, a torque command for axis 1 will still be of a lower priority with respect to, for example, the Heartbeat of axis 0.
Is my reasoning partially/completely flawed?
With only two nodes on each bus (IMU + RPi on one, RPi + ODrive on the other) then there is little possibility for message collision and so I doubt you will have any issues related to message priority.
The STM32 in the ODrive has a hardware Tx FIFO, if you send two messages at once then it will send one and then the other - they will not collide. Also the Heartbeat message is pretty low-rate so it makes sense to have that as high-priority.
You can check the CAN Bus Load at the RPi end with the
canbusload command, from the same
can-utils Debian package as
canbusload -rbt can0@500000 can1@250000 if you have two buses, one at 500k and the other at 250k
In the event that a CAN frame does collide, then the CAN hardware itself will detect this and immediately retransmit the lower priority message that had been suppressed.
I see, so I should not have problems.
Thanks again @towen
Sorry @towen for coming back at you.
I have previously successfully build my modified Firmware.
However, I realized that I had put
CONFIG_BOARD_VERSION=v3.5-48V in the tup.config file.
My board is actually the v3.6-48V.
So, if I change change that line into
CONFIG_BOARD_VERSION=v3.6-48V, then tup is not happy and says
tup error [string "Tupfile.lua"]:362: unknown board version v3.6-48V stack traceback: [C]: in function 'error' [string "Tupfile.lua"]:362: in main chunk [ ] 100% *** tup: 1 job failed.
Should I stick with the v3.5 in the tup config or is there something I am doing wrong?
You need v3.6-56V, obviously.
Ops , thanks @towen.