Cool but would it work on a Corexy?

Can-fd is backwards compatible with can2.0. Older can nodes can’t understand can-fd frames. Unless you can modify duet to send older type can frames, they don’t understand each other. Otherwise I’m sure they could be made to work with each other as long as the protocols are adapted.

Quinton: I’m not entirely sure how klipper manipulates the timers to maintain timings. It’s a bit complex, and very innovative, mechanism of the software. You should look at the developer documentation. It’s very well documented.

As far as integration into klipper is concerned, someone would need to look at their stm32 code and port over the serial protocol and timing scheme. And then make it work with the odrive base code. So far it would seem simple to get a small, supported mcu(like teensy LC or some atmega) and then configure it to run just 2 step dir interfaces. You could even solder it directly to the odrive header. :stuck_out_tongue:

Yeah, sorry, backwards-compatible is what I meant. A CAN FD node can send and receive both FD and regular CAN frames (without any reconfiguration), and the message ID part is almost identical, so even a regular CAN node can see that a message was sent, for the purposes of collision detection and priority. The only real difference is that FD can send more data in the payload, while the time taken to send a whole frame remains the same.
If you were to implement the CANsimple protocol on the Duet, then it would happily work with the ODrive, because CANsimple does not use FD frames. Whereas if you tried to do it the other way round (modify ODrive to pretend to be a Duet stepper driver) you’d probably run into a problem since ODrive can’t receive the FD frames.

You’d most likely have to modify the firmware on the duet to achieve this then since there’s no configuration options for it. Which would take some work.

Yes well… And I’m a mechanical engineer. I know Matlab quite well, but C++ and or python is not something I’ve used before. Hence my thorough thoughts on the step / dir each time. In theory that solution requires as few programming as can be.

But Ok honestly, can we discuss here a bit on the real performance increase when going klipper or duet CAN-FD?

As noticed the 3D controllers do the motion planning themselves already, so I think using the Odrives motion planning on top is probably more a problem then performance increase (motion is better but not the same as the 3D controller anticipated).

So with 16k pulses per rev and each step send by controller being the same as one pulse? It seems achievable and just as good as send by can or alike?

Feedback Control on position still possible I guess. Feed forward… Hmm I guess a no because it’s not clear what will come next.

Curious on your thoughts!

Encoders ordered, second motor to arrive tomorrow. Pi in the house… Starting to install stuff this weekend :hugs:

Realistically, there’s no real benefit. The biggest upside is that you can get feedback from the drive and change its parameters from the controller. Commonly most of the path planning takes place in the motion controller and all the drive has to do is follow instructions that are given to them.

You’re not going to get any meaningful performance increase from using digital communications compared to pulse train or analog voltage. They have more to do with reliability and control in the industrial space when the machine has access to information from every part of the machine. If you want to use the drive itself for motion planning then you need a new kind of motion controller. And at that point you’re building a bespoke system anyway…

Step/dir input will work fine between the 3D printer control board and the ODrive. The fundamental difference between stepper motion controllers and what ODrive “wants” is that Marlin/Klipper/etc assume constant position increments, so they send timesteps for each step. ODrive performs best with constant time between input commands.

In other words, it’s constant step at variable frequency vs variable step at constant frequency.

The downside to step/dir on ODrive is that it lacks any velocity or acceleration information. A position error has to exist before the ODrive will command the motor to move. A similar effect exists for stepper motors that are driven in open-loop mode (difference between current vector and rotor position causes torque), but stepper motors can react quicker than the ODrive control loop. There are arguments to be made here about torque and inertia and stepper driver dynamics but that’s beside the point.

One way around this is velocity and/or acceleration feedforward. The INPUT_MODE_POS_FILTER input mode in ODrive can mitigate the lack of information by calculating a velocity based on input_pos information and some other factors. The tantalizing aspect here is that somewhere, somehow, Marlin/etc DO know velocity and acceleration information - they calculate trajectories, after all. It’s just a matter of exposing that information as an output.

Is this a problem for ODrive use on a 3D printer? For regular 3D printing, probably not. 3D printer hardware is pretty well optimized at this point for what people expect an FDM printer to be capable of (barely good enough, but good enough is the goal!). You will run into flow limits for commercially available extruders before you hit the performance limit of ODrive with step/dir inputs, for example. You still get the benefits of closed-loop operation and better efficiency than stepper motors.

If your printer is up to the task of handling 500W+ axes instead of ~30W like a stepper, it may be worthwhile to investigate something other than step/dir inputs for ODrive.

3 Likes

Big thanks for your answer @PJohnson. Very clear.

At what kind of frequency is the Odrive sampling / looking at the step / dir signal if I may ask? It’ll help me determine at what kind of speeds I can still run vs the encoder settings?

Also I’m wording of you know more about the second order filter on the Odrive for step / dir?

Anyways, I now fully understand the die side of Strp dir only. I really like feed forward, so that’s a pity (I’m an NVH Engineer and making a model of my 3D printer and ultimately I would love to but the dynamic model into the controller.

But first things first. I think my steps will be to:

  1. get aquanted with the Odrive and get a setup running to test and try.
  2. use Step / Dir to see if I can hit enough precision in the motion
  3. try and print something ;-).
  4. take it from there to see how to improve as suggested by all of you. Thanks for that!

But now I’ll have to wait for all the hw first…:relieved:

If speed at all, I’d like to opt for a printer design that does really small layers (if at all) as indeed I see that extruders limit at the moment. All of this is not needed perhaps, but it sure is cool and learn all of this!

Hi PJohnson,

Do you have an estimate on how much slower Odrives control loop may react vs a stepper motor with step+direction?

I have an odrive on order now. I am initially planning to use a mix of closed loop BLDC and steppers on a 3d printer and they would need to be synchronized

As a first step over the next few weeks i hope to dig in to the Odrive and kliiper firmware source a little, to see if i can implement klippers communication protocol, command que, sync and step generation directly on the odrive.

Can you suggest what i need to read up on to better understand “Velocity and/or acceleration feedfoward” would the input still be step direction + velocity and acceleration, or i guess it could be each part of trapezoid move using External motion control ( ie Marlin / Klipper etc) allowing synchronized moves between odrive and other motor drives?

I haven’t looked at klippers motion planning source yet, but the developer doc’s make it sound like all the info required is in the move() class before the step timings are generated and sent to the MCU. Klipper Code flow of a move command

i am probably a bit out of my depth, but i will have a better look at this over the next few days and see if i have a chance of hacking something together.

Thanks

1 Like

@Quintin_Brand ODrive handles step/dir inputs via interrupts. The estimated limit is a 50kHz step rate, but I’m not aware if that has been tested. For reference, the ODrive control loop runs at 8kHz. Getting more than one interrupt per control loop cycle isn’t a problem - it’s just a larger input step. The limit here with step/dir is step size vs achievable max speed (due to the step rate limit). For the input filter, it looks like that is part of a newer firmware than master - my apologies. I’m not sure when it was added.

The 2nd order filter code is here on the devel branch. Based on the input filter gains and position/velocity error, feedforward terms are calculated for position, velocity and acceleration. It isn’t unique to the step/dir input, just a feature that could be useful.

I think you’re on the right track!

@bungle I’m not sure how much slower the ODrive control loop reacts compared to a stepper motor. Note that it isn’t unique to ODrive, it’s a characteristic of all feedback control systems. In the situation of ODrives and steppers on the same machine using step/dir commands, the “reaction speed” difference should not be enough to be noticeable. I think it would be noticeable if you were trying to fling the bed off the printer (but at that point you’re way beyond what a NEMA 17 is capable of).

In my opinion, there is not much benefit to implementing the klipper command protocol on ODrive vs using step/dir from a printer controller to ODrive. The information is the same, so the only difference is that it’s over a more reliable communication method.

I think it would be difficult to modify klipper such that it outputs step times and position/velocity commands in a synchronized way, but I could be wrong.

For the velocity/acceleration feedforward (really velocity is the most important), this is a good graphical reference.

For step generation, a trapezoidal velocity profile is made for a move command in the gcode. A position profile is calculated from the velocity profile. Then, step times are calculated to minimize the error between the “achievable stepper motion” and the desired position profile.

For the feedforward idea, in klipper, you’d take the position and velocity profiles and sample them at a fixed rate. In other words, if the move takes 1s total, slice that up into pos/vel commands for every 1ms of the move. Each position/velocity sample is then a command sent to ODrive. No need for step/dir inputs to ODrive with this scheme.

1 Like

Really really helpful again. So to try and summarize for me with the question if I got it right?:

  1. Sampling on the step / dir Odrive input is probly in range of MHz or at least high kHz range.
  2. a step / dir “pulse” triggers the interrupt (with time stamp “accuracy” of the MHz sampling). It can take up to about 50k events per second. The time stamps / trigger events / steps are converted to position. Furthermore the time difference between pulses are converted to velocity.
  3. the position and velocity is handed to the Odrive control loop which takes the last / current pulse received (e.g
    position info) in its 8kHz cycle. Therefore the control loop has no trouble when within a control cycle multiple pulses passed as it takes the latest / current position for the following cycle. This is beneficial because in this way one can’t miss out on steps in successive cycles for being bounded by 8kHz. So where at slow motor speeds it is just 1 step one can also handle multiple steps with one cycle for high rev. So no loss of steps dye to the 8kHz cycle.

Odrive for my application would be in position mode and the control using feedback makes sure the motor gets to the requested position by feedback.

In this view the 50k samples do have accurate time stamp information which is important to estimate the velocity. The 50k samples should be seen as the max steps a second the Odrive can handle steps. So 50k pulse / cps is max rev and therfor is an important trade-off between accuracy vs speed.

Looking at the control loop I have a bit more trouble to think this through, but thank you very much to point me to the actual code!

So what I like a lot here is that both position and velocity are taken into account. I’d think velocity is computed from the difference in the two last steps hence the MHz sampling.

With velocity taken into account as well I see no big impact in performance while being “only” 8kHz cycle. I guess it means that the acceleration is updated with 8kHz “sampling” where its amplitude changes in discrete steps. And here is the difference Towen pointed me at that if using the Odrive motion planning one could make nicer motion with for example a step on the jerk or even higher order derivatives?

Perhaps the second order filter I think @Wetmelon pointed at is perhaps a filter on the velocity estimate…

Hope this is all correct? I start to get a couple of ideas and hence the question up front: the 8kHz cycle is directly coupled to the amount of computations done or does it still have some headroom for additional computations in the loop?

I’m asking because I’d know how the 3D controller behaves in acceleration events etc :thinking:

That’s not quite it.

Every step pulse triggers an interrupt which increments the target position by a constant amount (configurable). No other actions are taken. The time stamp of the pulse is not recorded.

At a rate of 8kHz, the control loop reads the target position and applies control outputs to drive the motor to that position. It is during this phase that, if we know the inertia of the system, we can pre-compute the torque and speed curves we need to achieve a 2nd order (mass-spring-damper) behavior of the load. This allows us to “feed forward” those terms to the controller, instead of relying on only the error between target position and actual position. This significantly improves the control bandwidth, allowing for higher gains and faster settling time with less overshoot. This is the Input Filter that we’re referring to.

If we don’t know the inertia of the system, we could theoretically measure the # of pulses per 8kHz and estimate a desired velocity or acceleration, but this is often too noisy at slow speeds, so would need filtering anyway. The better approach is to guess / approximate the inertia and use the input filter.

Hmm, thx :wink: :wink: !

Ok I started checking the code again and wrote many things that I deleted again to now find myself reading the documentation on GitHub. I simply didn’t get that I could read a lot of the detailed functionality here ;-). OOPS.

The amount is more than enough to keep me busy for a while :wink:

I’m digging in to the code and start to see the connection between the dynamic model of my CoreXY to be and the feedback and forward implementation on the ODrive. Question before I go down the rabbit hole though:

The 8kHz control cycle: how much headroom is there left for additional computation with that cycle? Or will any operation immediately impact the cycle frequency? Here I’m focusing on the step / dir - position control.

Thx!

Not much. That being said, we’re doing a low level refactor next, which I suspect will wring out quite a bit more performance.

Hmm, ok, well I see two possible improvements for a CoreXY:

  1. When moving in X or Y different inertia are felt. On my design say X=0,5kg and Y=1kg. So the inertia feedback would benefit a split in both directions (requiring add and subtract of the two encoder signals too).
  2. I also computed the resonance frequencies of gantry - belt helt at Emotor system and could (try) build feedforward for the flexible modes too.

And the last thing I’m thinking about is how to determine 3D controller jerk allowing “instant” speed changes.

Did you get anywhere with your firmware? I am looking to build a pen plotter, so far I haven’t found a clear cut way to send gcode to an odrive.

No I did not unfortunately. Work has kept me awfully busy last year and it still does. No time fir hobby at the moment and the Odrive is still in its original box… :-(.

But step / dir is the easiest way for sure and if you use an SKR1.4 for example you can wire it directly to the board as it had pins to place a custom stepper driver.

I would recommend klipper if you are on marlin and want to switch. I am used to RRF, so I’d now would either buy a duet2 (with extension board as I have more dof to control) for it has direct connectors for step / dir or they and get RRF to run on the SKR1.4 (new possibility lately).

I think that the pulse train (step/dir) will contain more then enough frequency content to serve as a good control signal for the Odrive. The trouble will be to tune the combi of move and filament extrusion.

Hole this helps you into your journey!

Thanks for the info!

Here’s the one thing - I really want to be able to move the gantry by hand and have the firmware / software / controller or whatever know the new position.

Currently my only lead is linux cnc, even then I don’t think the Odrive board will report its position while in step/dir mode so I’d need a 2nd set of encoders maybe?

Any idea if that’s achievable?

There’s a you tube video on a odrive pen plotter.
Several actually.
Using step /direction .
Crazy fast to.
And he’s aprochable ,

Great thread.
But no one is asking about noise of the system.

Did anyone succeed at this. BTW, klipper does not only have step/dir. This is the low level commands. This is equivalent to distance, velocity and acceleration. It would be nice to close the thread with some conclusion. If this actually was already working.

queue_step oid=7 interval=7458 count=10 add=331