ODrive GUI to eliminate Shell CMD interface?

Given that the Odrive utilizes Python for commands via the CMD Prompt, is there projected development of a GUI (perhaps like the VESC tool) to make setting up the Odrive more user friendly? I was trying my hand at it but honestly, I don’t know enough coding to do it effectively.

It’s on the development roadmap, and we plan to do this soon :slight_smile:


That’s great news! Thank you for the update! Can’t wait for the release!

Hey, I’m new to the community (I just heard of ODrive last Wed. ordered mine Friday and it just arrived in the mail today). I just wanted to say I’m an experienced C# developer who has been coding in Python, well, on and off for the last 3 years, but, almost exclusively the last 4 months or so. On top of that, GUI development has been my primary focus. I just wanted to reach out and see if I could be of any help; with any part, that is, not that I’ll only help with the GUI.


Hey, that’s cool. And welcome!
But please be aware that a lot of us (if not most) in this community are using Linux. I love C# for the language and its well-polished design principles, but the thing that makes me hate it is that it is controlled by Microsoft, and (deliberately?) doesn’t work cross-platform, especially not under Linux. Mono sometimes works, but a lot of the major toolkits (especially WPF) have never worked in Mono afaik.
Can you work with PyQT instead? :stuck_out_tongue:

I was working on a GUI myself in PyQT, but it fell by the side due to other demands on my time :frowning:

1 Like

Sorry, I thought I already replied to this…

Thank you for the warm welcome! However, you have the mistaken C# with .NET. The .NET Framework is not cross-platform; however, .NET Core is Linux and Mac compatible. I can’t say I blame you for the hate on Microsoft, but, I learned it because in 90% of the enterprise realm, you’ll see Microsoft/Windows.

I’m not familiar with PyQT, though. I’ve spent most of my time working with tkinter, as none of my builds have really demanded any special themes or animations; just simple automation IU’s; think, calculator.

As for the community and their OS experience/preference; well, I’ll let you decide if you think that’s an issue for me. :grin:

Yes I was conflating C# with .NET, but I wasn’t aware that C# is really much use without .NET ? Can you make a GUI in C# without using .NET? Isn’t C# without .NET a bit like Java without a JVM?

I like QT as it gives the same Model/View/Controller design and programmatic data-driven UI building, without being tied to an (evil) vendor
You can have model-driven list views, tree views, table views etc. QWT gives you nice graph-plotting and slider/knob control widgets
And of course it’s available directly within Python via PyQT, so you wouldn’t need an extra interface layer to access the existing odrivetool libraries.

I love how in your picture, only two of your laptops are functional. :joy:

1 Like

Well, yes, but, no. The key detail you missed there was .NET Framework and .NET Core. You can read more on .NET Core here.

I’ll have to look into it, but, most of those things can be accomplished with numerous python modules.

I agree this would be the deciding factor, for me, to do the GUI in python (because the system is already utilizing it, that is). Other than that, it would’t be hard to do it in either language if you are essentially just sending the console command to the odrive over serial. It would basically be just wiring a button to send a serial output.

Low key, I hoped someone appreciated that. But when isn’t Windows updating?

So apparently you cannot make a GUI in .NET Core. So what’s the point of it at all? It might as well be Java. Why would anyone want to pollute their software with a proprietary binary dependency, if it doesn’t even do anything for them? :thinking:
At least with Java there’s OpenJDK, and it’s not trying to nudge all of my customers and collaborators towards a certain proprietary platform.
Seems like its main purpose is to make it easier to access your Azure Cloud Services from your Linux Webserver. And to lure unsuspecting developers to .NET land. :stuck_out_tongue:

Yes I’m actually quite impressed at how rich the tkinter landscape is, given that it uses Tcl/Tk, a doddery old UI framework from the 80s…! :slight_smile:

This was my attempt in PyQT. It only works over CAN, and probably only on works on Linux. (it’s pretty difficult to get a CAN interface working in Windows anyway!)
It’s fairly limited in what it can do, since you can’t query or change most parameters over CAN, at least with the current protocol. I’d like to do a version that works over CAN as well as the ODrive API (or better, put CAN connection into the ODrive API with a more complex/complete protocol)

The table is displaying a generic Python dictionary. The dial displays position setpoint and actual value, and the gauge displays torque (i.e. current) as a proportion of current limit. That doesn’t work yet, because there is no way to read the configured current limit over CAN, unless I add a command to the protocol/firmware.

1 Like

lol That stackoverflow answer was so out of date, the new answers are even old. .NET Core 3.1 is out. You can do WPF, Win Forms, UWP, mobile apps with Xamarin, it’s very powerful now.

Hey, if it ain’t broke don’t fix it; amirite? :upside_down_face:

Yep, don’t know jack about CAN. I understand what you’re attempting to accomplish, but, I don’t know CAN, so, any input would be talking out my ass lol. I’ll do some research though, because it’s becoming evident that I need to know about it.

This is hilarious.

I have Windows 10 in a virtual machine that I occasionally use for testing things. I swear that when I need to use it, I have to start the VM the day prior and begin the updating process, so I can use it tomorrow :rofl:

1 Like

Not a huge amount to learn. It’s a message-based protocol with 11-28 bits of message ID, and 0-64 bits of data. That’s it, literally. Everything has to be well packed to make most efficient use of it, so bitfields are common. For my GUI / CLI, I made use of Python’s pack/unpack for this.
Read the CANsimple documentation - there’s only a few commands, and the message ID format is pretty easy to understand.

The nice thing about CAN is it’s so robust, and it’s a shared bus, so you can have multiple ODrives working together. It has automatic retransmission and a priority system implied in the message ID (so a higher priority message with a lower ID will always get through, even if it collided with a message with a higher ID - the sender of the higher ID message will know that there was a collision and retransmit it) -0 but from an app programmer, all you care about is the message ID and data packet - everything else is handled in hardware.

It’s easy to test with a raspberry pi and a “PiCAN 3” hat

These are my basic functions for accessing the CANsimple commands in the documentation:

import can    # needs python3-can debian package or equivalent

#** odrive_cansimple_cmd()
# generic CAN command function for "CAN Simple" protocol
# see: https://github.com/madcowswe/ODrive/blob/RazorsFrozen/docs/can-protocol.md
# @param node_id: ODrive assigned CAN bus node ID, one per axis
# @param cmd_id: Command ID as per messages table
# @param data: Python list of signal values, according to messages table
# @param format: Python Struct.pack format string for signals in 8-byte CAN message, encoded according to signals table
# @param RTR: Remote Transmission Request bit - set to request "Get" data from ODrive

def odrive_cansimple_cmd(bus, node_id, cmd_id, data=[], format='', RTR=False):
        data_frame = struct.pack(format , *data)
        msg = can.Message(arbitration_id=((node_id << 5) | cmd_id), data=data_frame)
        msg.is_remote_frame = RTR
        msg.is_extended_id = False

#** odrive_cansimple_receive(can.msg)
# Pass in a CAN message to be decoded into CANsimple node ID, command ID and data packet
def odrive_cansimple_receive(msg):
        raise ValueError("Ignoring extended-ID: %d" % msg.arbitration_id)   # we don't support extended IDs in CANsimple, so discard these messages as$
        raise ValueError("Ignoring remote frame request: %d" % msg.arbitration_id)   
    node_id = (msg.arbitration_id >> 5) & 0b11111   # upper 6 bits
    command_id = (msg.arbitration_id & 0b11111)     # lower 5 bits
    return (node_id, command_id, msg.data)

Oh ok, I’ve used a similar setup interfacing a hydraulic crimp-tool with an RFID badge scanner. I had to learn how the scanner communicated in order to decode the badges so only authorized users could activate the device. But we may want to take this conversation elsewhere. We’re getting bit off topic lol.

Hi Towen, Hi CGarrett, I’d like to put the both of you in a pub with a few beers, and I think the outcome could be spectacular :laughing:

Joining forces may be a better way to provide a solution for the GUI!

Regards Jerry from “partial lockdown .AU” :mask:


lol Hey Jerry. Make it a dispensary and you got a deal :joy: I drank enough through my 20s lol.

As for joining forces, I’d gladly work with someone like towen. He seems quite experienced and not unyielding to suggestions or compromise. Ideal team-mate to me.

Regards, Claude (Kyle) from “It’s all a hoax! The government is trying to strip you of your rights! Don’t wear a mask!, AL” :rofl: