CAN Interface Available for Testing

Hey Wetmelon, thanks for all the work on implementing CAN for Odrive!

I was reading through this entire post, some of the PR’s on your fork, and the PR you have on the main Repo. What is the general plan for getting your CAN work in the master repository? Is there a list of things that need to be fixed, validated, and tested?

I was wondering because after reading this thread, it seems like a lot of people have not had an easy getting a test setup for CAN. I have done quite a bit of work with a PCIe PCAN card using SocketCAN, but was thinking about developing a quick STM32 and SN65HVD242D board or maybe an existing board/shield combo. Do you think it is worth developing something new or using something existing? Either way, I would like to set that up and create a pretty decent write-up so that we can get more people using CAN without a lot of troubleshooting on a bunch of different setups. What are you thoughts?

There are a couple of us setting up a CAN rig for testing in the RazorsFrozen branch. We will be testing with both a Teensy and a Raspberry Pi (with CAN hat and cantools or socketCAN). It’s always worth doing write-ups and more testing :smiley:

Hi everyone!

Is there at the moment the possibility to feed the watchdog through CAN?
Thank you :slight_smile:

Hi Matteo,

The watchdog is fed any time an axis receives a valid message.

Hi @Wetmelon, thank you!

Is there also any possiblity to use the ramped velocity control with CAN messages or any workaround I could try?

You can set the input and control mode with MSG_SET_CONTROLLER_MODES then use input_vel, but it seems you can’t change the acceleration limits…

1 Like

Hey, quick question.

Vel FF
Current FF

Anyone know what the above signals are for? They can be found in the ‘Set Pos Setpoint’ command. Thanks.

These are feedforward terms for the velocity and torque controllers, and are very optional. For example if you are holding a load, you could set a torque feedforward equivalent to the constant torque produced by the load, so the position controller has less to correct for. This can help to get better positioning accuracy without relying on a high integral gain.
They would normally be used by an automated controller that is aware of the motion profile it is sending to the robot.

1 Like

I’m looking at the CAN implementation, noticed that the 11 bit IDs are split into 6 and 5, so up to 64 devices and 32 possible commands. Of which, 24 CAN IDs are already defined.

I usually find it necessary to send other values to motor drivers from a master. I’ve been doing this over multidrop serial data in the past. CAN seems to be a better choice going forward.

For example:

  • PID values
  • Current Limit value or max PWM value
  • Maximum position error limit
  • Set motor stop on position error or limit switch
  • Reset position to zero (or other value) on position error or limit switch

These are some of the things I need to do when I’m homing, then I send new values when I’m in runmode. I prefer to allow the master to store these values and not rely on the motor driver to store them. Less things to update when things change.

Is there any plan to use up the remaining 7 or 8 IDs?

Those sound like decent reasons :slight_smile:

Also we’ve implemented homing, so I can probably make a “home axis” command or similar.

Thanks for listening.

Here, have implemented CAN control long ago and over time, ran out of bus bandwidth @ 500kbps. Couldn’t go the 1Mbps due to cable length requirements. Eventually was telescoping the bus over 10/100 Ethernet and fiber for longer hauls, but still had to stick to 500kbps.

The importance of ID priority cannot be understated on a busy bus. IDs closer to 0x000 get priority. Your ID scheme and support of CANOpen might be questioned in the future, when a busy bus is encountered. I had set packet IDs lowest as I cared about set-position, being updated every 5ms - ~18ms, depending on the type of device I was controlling and how critical the motion coordination needed to be.

I’ve seen CAN buffers overflow (older microcontroller devices were slow and had few frames in the buffer) and had to implement extensive ID filtering in the devices as well as the Eth to CAN bridges. If you get to that point with CAN, you’re pretty much doomed, and better off looking at CAN FD or parallel busses.

If I were to re-implement a protocol now, I’d swap your node ID and command ID, and make ‘Set Position Setpoint’ CMD ID = 0x001, saving estop = 0x000. Then go up from there, based on the time sensitivity of the CMD.

Certainly not telling you what to do, but sharing some insight from doing motion control over CAN, since '04. Here, was all brush DC servo motors, max out at 16 motors on one bus.

When I type odrv0.axis0.config.can_node_id = 3
I get " AttributeError: ‘RemoteObject’ object has no attribute"

Do I need a firmware update?

You need to flash the firmware as detailed here. However, the firmware CAN branch (linked above in the original post) recently became unavailable. Hopefully it’s back soon, since im also looking to use CAN as well.

I like your biped project btw, looking forward to your next vid :grinning:.

1 Like

All of the CAN features have been integrated into devel now, so please use this branch

1 Like

Has anyone had success getting CAN communication to work on the devel branch? I’ve got my V3.5 48v dual axis odrive flashed to the head of devel. I’ve got the odrive’s CAN pins hooked up to a CAN network with 2 raspberry pi zeros connected via MPC2515 CAN boards

The raspis have the CAN bus initialized as follows :

sudo /sbin/ip link set can0 up type can bitrate 250000

I configured the odrive to have the same CAN data rate and I set each axis to have a custom can ID then saved the configuration (as shown in the CAN documentation).

I can send CAN messages between the raspis just fine but when I connect the odrive CAN pins then the messages won’t come through between the two raspis and I don’t see any heartbeat messages from the odrive axes. When I disconnect either of the odrive CAN pins from the CAN bus then the raspi CAN messages that didn’t come through show up all at once on the other raspi. I’ve tried all possible combinations of the odrive CAN terminating resistor dip switch along with the CAN resistors on the raspis CAN boards. I’ve also tried just having one of the raspis hooked up to the odrive with the same results. Anyone have any ideas? Thanks.

Do you have a shared ground between all 3? Make sure you’re using the GND near the CANH / CANL header on ODrive, and make sure the resistance between CANH and CANL (with everything off) is 60 ohms

Wetmelon, thanks for the fast response! They do have a common ground (raspis are powered off of the odrive 5v supply). I switched the ground pin to the one by the CAN pins (never would have thought of that being an issue). Resistance was 120 ohms with the power off, so I connected the other raspis terminating resistor and that brought to 60 ohms. Power cycled and got the same result as my post. There isn’t any CAN command that needs to be sent to start the heartbeat messages from the odrive? Beyond that it seems like something is fundamentally wrong because the odrive blocks the can messages between the raspis. Any other ideas? Thanks!

Nope. Although you do have to make sure you haven’t configured it to use i2c instead of CAN.

If you connect just one Pi, do you get any data? Or can you see the ODrive transmitting with an oscilloscope or logic analyzer?

To confirm, what message IDs is everything sending?

Thanks for the troubleshooting Wetmelon! I was finally able to fix the problem. It turns out that the MCP board as two clock frequency modes 8MHz and 16MHz. For some reason the odrive only works with the 8MHz mode. I was able to figure this out because I hooked up an old arduino CAN rig I had put together with the same MCP module as the raspberry pi zeros and it was able to finally see the CAN messages from the odrive. Looking at the differences between the arduino code and the raspberry pi I found the frequency mode discrepancy. It is a parameter in the arduino code, but is buried in the boot/config.txt on the raspberry pi. So to fix I changed the MCP configuration line from

dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25,spimaxfrequency=500000
to
dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25,spimaxfrequency=500000

And now the raspberry pi zeros are seeing the odrive CAN messages! I took a peek in the can init code interface_can.hpp and it looks like the can code is using 42MHz. I’m not sure why this makes it only work with the 8MHz clock for the MCP CAN board, but I guess as long as it is working it’s not a big deal.

Ah, there is a physical crystal oscillator on the MCP2515 CAN hats. I guess you have to make sure your Pi knows what frequency it is or it’ll talk at the wrong baud rate?