Hello all,
I have an Odrive v3.6 on the latest firmware. Im driving two motors on closed loop which are coupled together via a differential gearbox.
What I want to achieve is to rotate both at the same speed but opposite directions most of the time but also control the drift/offset between them according to an analog signal.
Currently I am controlling one using velocity control and I have the other mirroring the position of the first (mirror ratio -1). This works beautifully. However, I have no idea how to tell one of the motors to drift/offset. At some point I believe I achieved it with set_linear_count via UART, but it was buggy as hell, probably because the serial buffer was overwhelmed. I am using an ESP32 to ask odrive for position feedback and then tell it to offset using the “esl” command.
Is there a better way to do this? Can I somehow use the Odrive’s analog input feature? Would the above work better using the CAN interface?
Thank you
The other option I might have is using the Native protocol over UART by running it in micropython on the ESP32, but I have never done this so not sure if its possible. I am also not sure if it will be faster and more reliable compared to simply sending UART commands
CAN will definitely be faster overall, though I think Micropython may be a bit of a bottleneck here – not entirely sure though. But you wouldn’t want to use set_linear_count, you’d want to just use position control in circular mode.
Ok, I won’t attempt micropython then. I thought maybe the native protocol would be more reliable but can’t sacrifice speed.
How do I guarantee smooth rotation in position control? Do I make sure to update position at least twice per rotation faster than the motor rotates? Does this mean that I can’t use mirror mode so I would have to send twice as many messages?
Correct, you wouldn’t be able to use mirror mode. You’d need to stream your position at a few hundred Hz minimum, giving velocity feedforwards so that the ODrive doesn’t slow down upon reaching the new setpoint.
I’m not being successful in controlling it this way
I’ve set the controllers on circular and I set a timer up to fire every 1 second, sending the two following commands. The motors are in position control.
odriveSerial << "p 0 -0.9 0.5" << '\n';
odriveSerial << "p 1 0.9 0.5" << '\n';
the way I understand it is that it should mean the motors try to do 0.9 turns every second at the speed of 0.5 turn/sec. I tried the q command too. I tried INPUT_MODE_TRAP_TRAJ instead of INPUT_MODE_PASSTHROUGH. I tried setting the turns to 0.5 and 1.1, increasing the speed, increasing the timer speed. Nothing works. The motor simply turns to a position and stays there.
Do I need to give increasing turns, even though I set the circular position to true?
Im also at the process of switching over to CAN protocol, just waiting for the right interface chip to arrive.
I believe I figured it out. Im using the q command and PASSTHROUGH, but I need to stream 4 positions (or maybe I could do 3 to send less commands) per revolution. The reason being that sending 1 position keeps it stationary as long as the position doesn’t change, sending 2 positions has inherit ambiguity (one or both motors may turn opposite to what I want) so I need to send q command to positions 0.25, 0.5, 0.75 and 1. As long as the timer is set at the correct speed, the rotation is smooth.
However, this has another issue. If for whatever reason one motor stalls, the other will keep rotating 
This has the potential of throwing my alignment off. Not to mention that the ISR of the timer can’t do floats, so will probably need to move this to the main loop.
Hi! Oops, sorry if I wasn’t more clear – yes, you need to be streaming position setpoints extremely fast for this method to work – ideally at least 100Hz. You should be using PASSTHROUGH, since POS_FILTER and TRAP_TRAJ won’t respect your velocity setpoints.
Agreed regarding the motor stall – the “right” way to do this would be to use CAN, where you can set up ~1kHz feedback messages, and monitor the encoder positions of both motors and set the relative positions of the follower to match the leader – you can send position setpoints much faster over CAN anyways. But if your microcontroller can’t do floats in the ISR, it may take a beefier microcontroller anyways 
1 Like
Well, Im using an ESP32 which by default does not allow floats in ISRs, but there is a config option to enable just that. I will try it as soon as I implement the CAN comms.
For now Im trying to skip the middle man and see if its relatively easy to change the firmware and add an option to map an ADC input to a float offset value that gets added to the position mirror option. This way I can input an analog signal to the Odrive and skip the extra MCU altogether which would be ideal.
Makes sense, that sounds like a good approach!
So I was successful at changing the firmware so that an extra encoder offset, initialised to 0, gets added to during mirrored mode to position.
Now one motor can operate in position or velocity mode and the other is in position mirror mode, with the extra parameter changing according to one of odrive’s analog inputs.
Im assuming that the analog in is read as fast as the loop, i.e. 8KHz, which is ok for my purposes.
Great!
Analog is read at 1kHz but that’s still pretty fast.
Still, 1KHz is fast enough for what I need it.
I’ve set one pot to control velocity of M0 and another pot to control this new offset of M1, which is set in position mirror of M0. It works great. I can actually hear when M1 speeds up or slows down to match M0, depending on what the 2nd pot tells it to.
However I have an issue. The ADC has an offset. When the pot is at zero or when the ADC is grounded, it reports something like 0.08 as speed. Im assuming its a calibration issue. The end result is the M0 moving when its not supposed to.
Is there a way to calibrate the ADC? I know there’s no deadzone feature. The alternative I thought was to set the min ADC mapped value to something negative, so whatever the ADC reads at zero position is mapped to zero.
The other issue I have is that on boot, the two motors start their calibration sequence, including searching for the encoder index. I would assume that this means they always have the same relative to each other positioning. But they don’t. I even power the odrive off, manually set the 2 motors at the angles I want and then power it on, and they will find a new slightly different position to start at. I need them to turn on and start at the same relative angular position, which is to be considered the zero point of the 2nd pot. I tried using the index offset option, but Im not sure this is the correct one.
Great to hear!
I think you’d have to implement the ADC calibration yourself. Generally I strongly recommend against analog inputs, as they’re noisy and can be influenced by EMI from the motor.
If you want both motors to have the same zero, then yes you need to use absolute_setpoints, and set index_offset and use_index_offset.
1 Like
Is absolute_setpoints an option in v3.6? Because I can’t seem to find it in the docs
I assume that the index_offset is in counted in turns, as its a float32.
Oh oops – yeah sorry, forgot that wasn’t a thing in 3.6. Should be index_offset+use_index_offset then.
1 Like