How to intentionally cause a Motor Error easily

Hi guys,

We’ve tested a 4-wheeled rover today, which is driven by a pair of ODrives v3.6 24V. The main computer communicates with the ODrives over CAN.
While commanding the rover with the remote control, I noticed the rover become weaker and weaker, and at some point we noticed that only one of the wheels is spinning, the others are idle. The main computer should command all four wheels in unison.
A while later, all four wheels were idle, so we stopped and I went to see what happened. Unfortunately, our CAN interpretation code is very rudimentary. We’ve written a custom webservice, which decodes Heartbeat messages from the ODrive axes, and it told us:

	"back left": {"busCurrent": 0.0, "busVoltage": 28.24, "controllerErrors": 1, "encoderErrors": 0, "motorErrors": 1, "pos": 92747.75, "spd": 0.0, "state": "IDLE"},
	"back right": {"busCurrent": 0.0, "busVoltage": 28.20, "controllerErrors": 0, "encoderErrors": 0, "motorErrors": 1, "pos": 91969.98, "spd": 0.0, "state": "IDLE"},
	"front left": {"busCurrent": 0.0, "busVoltage": 28.21, "controllerErrors": 0, "encoderErrors": 1, "motorErrors": 1, "pos": 96183.34, "spd": 0.0, "state": "IDLE"},
	"front right": {"busCurrent": 0.0, "busVoltage": 28.21, "controllerErrors": 0, "encoderErrors": 0, "motorErrors": 1, "pos": 92925.57, "spd": 0.0, "state": "IDLE"}}

Sorry for the unfamiliar output, this is what our program decodes from the Heartbeats and a few other queries over CAN.
I did not implement reading the specific errors via the CAN Protocol’s Get Motor Error / Get Controller Error etc.

I will do that now.

But how do I test it? How to deliberately put the odrive in an error state, e.g. a motor error, without using the USB connection?
I though about e.g. disconnecting one phase, or something like that.

Probably the easiest way is to just pull power - it should throw an undervoltage error. Or to drop the vel limit on the motor to zero while it’s spinning.

Also, you’re running a 24V ODrive at 28V? You should absolutely not be doing that, that’s an easy way to cause the board to blow.

Thank you, @solomondg - I understand that these two methods will trigger a Controller error, right? Ideally I wanted to trigger a motor error, since that’s what happened on the field, just to be sure that the next time we go to the field, we’ll have the debugging code ready.

As per the voltage, thank you for noticing. The maximum voltage allowed for an ODrive is limited by the bus electrolytic caps and the power MOSFETs in the H-bridges, right? I don’t have the ODrives in front of me, but if things haven’t changed since v3.4, the limits should be 25V (caps) and 30V (MOSFETs). We’ve run our ODrives at full battery several times (29.4V), no explosions, so either the caps had some leeway and we were lucky, or they have been upgraded in v3.6. In any case, thank you, I will check thoroughly before proceeding.

If you drop the current limit to zero while the motor’s moving, it’ll trigger a CURRENT_LIMIT_VIOLATION - that’s a motor error. Alternatively, you could disconnect the motor’s C phase and run resistance calibration - that should cause an unbalanced phases error.

When switching, there are small voltage spikes that occur during each switching edge. These are a function of the bus voltage and current - they will likely be >5V in magnitude, which is much higher than the voltage rating of the MOSFET. Exceeding the voltage rating like this will put the FET in avalanche breakdown - this will clamp the voltage, but it’ll cause excessive power dissipation in the FET and will degrade the FET junction. Over time, this will cause the FETs to fail, and likely fail catastrophically (such as a fail-short). I’d strongly recommend switching to a ODrive v3.6 56V or (even better) an ODrive S1, otherwise it’s really just a matter of time until those FETs fail short. Make sure you have a fuse on the ODrive DC+, at the very least.

Thank you, the current limit thing is very doable, and I can easily setup it with what I have.

In fact we were able to trigger the issue again, and I need further help, unfortunately:

  1. when the errors occur, I’ve made a web UI to call the respective CAN method to clear the errors (0x018 Clear_Errors, and later I tried 0x016 Reboot ODrive). Neither of these seem to work - the CAN message goes through, I get a success status for the call, yet the errors remain. The rover is stationary. This is the code I’m using:

    bus = can.Bus("can0", bustype="socketcan")
    db = cantools.database.load_file("odrive-cansimple.dbc")
    
    def clearErrors():
        msg = db.get_message_by_name("Axis0_Clear_Errors")
        data = msg.encode({})
        msg = can.Message(arbitration_id=msg.frame_id | (CANnodeID << 5), is_extended_id=False, data=data)
        try:
            bus.send(msg)
            return True
        except can.CanError:
            return False
    

    when I call clearErrors(), it returns True, but the errors remain and I can’t change the axis state to closed loop control. Firmware flashed onto the odrives is v.0.5.6.

  2. The errors I got were very strange, e.g. three of the motors had SPINOUT_DETECTED as a controller error, and a motor error is 0x1100 0000, i.e. SYSTEM_LEVEL+UNKNOWN_TORQUE or’ed together. The fourth wheel had just the SYSTEM_LEVEL bit on, no encoder or controller errors. The three wheels with SYSTEM_LEVEL+UNKNOWN torque are likely fixable, I have some idea what to tune reading from other similar threads in this forum. But what could be the reason for the one with lone SYSTEM_LEVEL error?

As per the VBatt dangerously high - we definitely cannot change the ODrives anytime soon, but as a short-term strategy I will not charge the battery to more than 25V, and we’ll replace it with a 6S one.

Sorry, disregard the last message. After further debugging, the issue was somewhere else entirely - the python code as above works, it was just not called correctly.