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
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.
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?
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.
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 .
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!
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?