Full workspace for Ginkgo CAN + ODrive control debugging.
This directory is meant to be a practical bench environment for:
- direct motor bring-up with the Ginkgo USB-CAN adapter
- ODrive CANSimple testing without ROS
- ROS 2 bridge testing with the
ginkgo_odrive_bridgepackage - documenting the motor and ODrive configuration in one place
Source: Wikimedia Commons, public domain. Useful as a quick reminder of the BLDC + electronic commutation model that the ODrive is controlling.
Source: Wikimedia Commons, public domain. This is a simple way to visualize the shared CAN bus concept used between the host, adapter, and ODrive nodes.
Source: Wikimedia Commons, CC BY-SA 3.0. This helps explain why the current position setup uses trap trajectory instead of a raw position step.
If your Markdown renderer does not display remote SVG images, open the links directly in a browser.
Ginkgo_Odrive/
README.md
requirements.txt
ginkgo_tools/
ginkgo_motor_tester.py
odrive_ginkgo.py
read_encoder_once.py
telemetry_monitor.py
position_step_test.py
odrive_config_GIM8108-48_24V_clean.txt
ros2_ws/
src/
ginkgo_odrive_bridge/
ginkgo_odrive_bridge/
launch/
config/
Python_USB_CAN_Test_64bits/
ginkgo_tools/Standalone Python tools and the PyQt6 GUI for direct CAN debugging.ginkgo_tools/odrive_ginkgo.pyShared abstraction layer for ODrive CANSimple messages over the Ginkgo adapter.ginkgo_tools/odrive_config_GIM8108-48_24V_clean.txtClean working notes for the GIM8108-48 motor and the current ODrive setup.ros2_ws/src/ginkgo_odrive_bridge/The ROS 2 bridge package that maps/joint_statesto ODrive CAN commands.
cd /home/gerardo/Projects/Robotics/Ginkgo_Odrive
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txtpython3 ginkgo_tools/ginkgo_motor_tester.pypython3 ginkgo_tools/read_encoder_once.py --node-id 0x10
python3 ginkgo_tools/telemetry_monitor.py --node-id 0x10 --interval 0.5
python3 ginkgo_tools/position_step_test.py --node-id 0x10 0.10 -0.10 0.00From this workspace root:
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build --packages-select ginkgo_odrive_bridge --symlink-install
source install/setup.bash
ros2 launch ginkgo_odrive_bridge joint_state_bridge.launch.pyThe default bridge parameters live in:
ros2_ws/src/ginkgo_odrive_bridge/config/joint_state_bridge.yaml
The default node IDs there are 0x10, 0x11, and 0x12, which matches the multi-axis pattern already used in the project.
The cleaned motor configuration file is:
ginkgo_tools/odrive_config_GIM8108-48_24V_clean.txt
The current confirmed CAN configuration in that file is:
- axis node ID:
0x10 - CAN baud rate:
500000bps - protocol style: standard 11-bit ODrive CANSimple
The current configuration uses:
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_POSITION_CONTROL
odrv0.axis0.controller.config.input_mode = INPUT_MODE_TRAP_TRAJThat is a good bring-up choice because:
- it gives bounded acceleration and deceleration instead of an abrupt position jump
- it reduces mechanical shock on the arm, gearbox, couplers, and mounts
- it makes bench tests more predictable and easier to repeat
- it is easier to reason about when your host is sending position targets in turns
In this mode, the host sends position setpoints and the ODrive internally generates a motion profile using:
trap_traj.config.vel_limittrap_traj.config.accel_limittrap_traj.config.decel_limit
That is why the current standalone tools and ROS bridge are position-oriented: they all eventually send Set_Input_Pos CAN frames.
If you switch to torque control, both the ODrive configuration and the host abstraction change.
On the ODrive side, the important changes are:
odrv0.axis0.controller.config.control_mode = CONTROL_MODE_TORQUE_CONTROL
odrv0.axis0.controller.config.input_mode = INPUT_MODE_PASSTHROUGHYou would usually stop thinking in terms of target turns and start thinking in terms of:
- commanded torque in Nm
- current limits
- thermal limits
- bus voltage behavior during acceleration and regen
On the host side, the abstraction changes from:
- "send position target in turns"
to:
- "send demanded torque in Nm"
In practical CAN terms, that means moving from Set_Input_Pos (0x0C) to Set_Input_Torque (0x0E).
If you wanted this workspace to support torque control cleanly, the next software changes would be:
- add torque-command helpers to
ginkgo_tools/odrive_ginkgo.py - add a torque test CLI script
- add torque widgets to the GUI
- make the ROS bridge configurable so it can choose position or torque commands
The Ginkgo adapter and the SN65HVD230 solve different layers of the stack.
The current stack is:
GUI / CLI / ROS bridge
-> odrive_ginkgo.py
-> ginkgo_can + ControlCAN.py
-> Ginkgo native driver
-> Ginkgo USB-CAN adapter
-> CAN bus
-> ODrive
The adapter already contains the host-facing transport layer, so your Python code can open a device, send frames, and receive frames through the vendor library.
The SN65HVD230 is only a CAN transceiver. It is not a complete USB adapter and not a CAN controller by itself.
That means the stack becomes something like:
GUI / CLI / ROS bridge
-> ODrive CAN message encode/decode
-> backend for a CAN controller
-> CAN controller hardware
-> SN65HVD230 transceiver
-> CAN bus
-> ODrive
So the abstraction changes like this:
- the ODrive CAN message layer stays mostly the same
- the Ginkgo-specific transport layer disappears
ControlCAN.pyandginkgo_can.busare replaced by a new backend
Examples of replacement backends:
- Linux SocketCAN
- a microcontroller with a CAN peripheral and a serial command bridge
- a different USB-CAN interface with its own Python or C library
In other words, encode_set_input_pos(), CAN IDs, and telemetry decoding can stay almost identical, while the low-level send/receive implementation is swapped out.
This workspace now includes the Ginkgo vendor libraries for:
- Linux
- Windows
- macOS
The Linux native files are expected at:
ros2_ws/src/ginkgo_odrive_bridge/Python_USB_CAN_Test_64bits/lib/linux/64bit/
ros2_ws/src/ginkgo_odrive_bridge/Python_USB_CAN_Test_64bits/lib/linux/32bit/
The standalone tools can discover the vendor folder there automatically.
ginkgo_tools/ginkgo_motor_tester.pyginkgo_tools/odrive_ginkgo.pyginkgo_tools/odrive_config_GIM8108-48_24V_clean.txtros2_ws/src/ginkgo_odrive_bridge/ginkgo_odrive_bridge/joint_state_bridge.pyros2_ws/src/ginkgo_odrive_bridge/config/joint_state_bridge.yaml
- ODrive CAN protocol: https://docs.odriverobotics.com/v/latest/manual/can-protocol.html
- ODrive overview and controller inputs: https://docs.odriverobotics.com/v/latest/manual/overview.html
- ODrive CAN guide: https://docs.odriverobotics.com/v/latest/guides/arduino-can-guide.html
- TI SN65HVD23x family overview: https://www.ti.com/product/de-de/SN65HVD231/part-details/SN65HVD231DR
- BLDC motor image: https://commons.wikimedia.org/wiki/File:EC-Motor.svg
- Bus topology image: https://commons.wikimedia.org/wiki/File:BusNetwork.svg
- Trapezoidal velocity profile image: https://commons.wikimedia.org/wiki/File:Jerk_loi_mouvement_vitesse_trapezoidale.svg