Using Analog Input to control motors

I am trying to use multiple ODrives to control a cable robot. The four boards will be fed by a Quanser QPIDe Data Acquisition Device. The Quanser can only give out simple analog outputs. So, my question is multi-faceted.

  1. is it even possible to control both motors of an Odrive with only analog inputs? if so, in what control mode?
  2. how would you test such a system? would it be okay if I just attached a basic circuit (with variable resistance) to the analog input pins and then tested the system using differing resistances? or do I need something that can input a variable voltage?

It seemed like there was another with a similar issue, but his question hasn’t been answered: Analog Velocity Control not working for me

I don’t know enough about the ODrive to know where to begin, so I am asking here before I start trying to edit firmware (which I assume is necessary to get a system like this working).

@Riewert, I remember your project was using analog inputs from load cells. I was wondering if you can give some advice to neelpuri.

Thanks for summoning me. From my experience:

  1. Yes that is perfectly possible. The best way is to make some changes to the firmware in Communication, add a make_protocol_function() or make_protocol_property(). From what I understand it is also possible to use the odrv0.config.gpio#_pwm_mapping() functions, but I don’t have experience using them.

  2. You can read the GPIO values from your PC, using stock firmware, and write a control loop in python to test your control solution without modifying the firmware. Should work just fine. Just call odrv0.get_adc_voltage(#).

Lastly; be careful you don’t accidentaly fry any of your GPIO ports. Remember they are 0 - 3.2V (4096 bits). I think they are 5V tolerant, not sure, but the readout will not increase above 3.2V.

Thanks so much for your help. I, however, have no idea what you are talking about with your response to the first part of the question. I don’t know what it means to “add a make_protocol_function() or make_protocol_property()”.

After reading your comment @Riewert, this is what I was able to do:

odrv0.config.gpio3_analog_mapping.max = 5000

odrv0.config.gpio3_analog_mapping.min = -5000

odrv0.config.gpio3_analog_mapping.endpoint = odrv0.axis0.controller._remote_attributes['pos_setpoint']



But I guess I shouldn’t have done that before I knew how the functions worked. Nothing seems to have broken, but I can’t control the motor with the voltage input through GPIO3. Right now I just have the ability to vary the voltage input to GPIO3 between 3.3 and 0 volts. But changing the input does literally nothing other than change what I get when I run odrv0.get_adc_voltage(3).

I was able to write a python script that reads the value input to GPIO3 and control the motors through that. This, however, requires that I have a computer connected to each ODrive and have the script running in the background. This makes my processing very slow. The robot I am building needs to input information from the payload to the Quanser, have the computer compute the changes needed and then have the Quanser send commands to the ODrives. This is made significantly slower and more difficult if the output has to go from the computer to the Quanser and then back to the computer to be decoded.

I have tried to read through the firmware documentation but I don’t have nearly enough experience to understand what is going on in there. Any help as to what changes I have to do and where would be amazing. Thank you so much for any assistance you can provide.

No problem, I understand what you are going through.

  1. I have no idea how odrv0.config.gpio3_analog_mapping.endpoint works, but from what your saying, maybe try making a mapping for gpio2 and gpio4. I noticed that the numbering of the GPIOs is not always consistent. I don’t know of anybody who has actually used the mapping functions… @Wetmelon Also, googleing led me to:

  2. Get the firmware to compile on your computer. When that works, go to and change the function on line 112. The function is called by line 175, and is visible from your python code under odrv0.test_function().

I am trying to achieve something similar, so maybe the function I am writing helps as a reference (though I haven’t tested it yet). Odrive and Java

I guess the ultimate objective to get a control loop running on the ODrive, but I’m not sure what the best place to do that is.


It seems like the analog_mapping function is not working for me and doesn’t seem super well documented. So I doubt I will ever get it properly working. So, editing the firmware it is.

A slight issue, however, is that I don’t know how to compile the firmware (I actually don’t even know what that really means). I tried to go through the setup guide for windows on the documentation page here. But I don’t know if I downloaded the right materials in the right places because I don’t know how to use them in the first place.

I was able to download the firmware master and I can edit the code. But I am having issues with flashing the experimental firmware to the board. Whenever I’ve tried to flash the new code I bricked the board and had to completely reflash the master from here. Essentially I am asking if I have to compile the whole master (with my updates) into a single .hex file and then flash that? or if it is possible to flash a single .cpp file as an update to the old firmware? I can’t seem to find an answer online because I don’t know really anything about embedded systems.

Once again, thank you so much for all the help you have already given. You probably don’t know how much of godsend this is.

Yes, you need to compile the whole .hex file (even for the smallest changes). The easiest way to do that for me was through Visual Studio Code. How far are you getting with the compilation? Be sure to create a copy of tup.config for you board based on the tup.config.default file.

Also, how are you tranfering your code to the Odrive? Have you tried using the DFU mode over USB, by running odrivetool dfu custom_firmware.hex from the folder where the .hex file is? That works quite reliably for me.

I am currently in the process of working out how to compile the firmware in VSCode. But I ran into an issue that I can’t seem to surpass. I made a post about it here.

I think I correctly copied over the tup.config.default file and made it into a tup.config file correctly.

For flashing the firmware I was trying to use odrivetool dfu (file path) but that resulted in me bricking the board. The tool erased the old firmware and then crashed immediately afterward, resulting in a board with nothing on it. That meant that I couldn’t even run odrivetool dfu to put the firmware back on the board. So, I used the Upgrading firmware with a different DFU tool instructions to restore the firmware. I am more confident in my ability to flash the firmware than to edit it.

The main holdup right now is simply getting the firmware to compile into a flashable hex file. Which I am, slowly, making progress on.

1 Like