Feature request: add klipper MCU input mode

Ok, point taken! I don’t know much about this world, but I’m always surprised when I see the price of real CNC gear compared to 3D printer stuff.
I’ll accept there is something that can be done here. But neither the B-G431-ESC1 or the Powershield will be up to it, I’m afraid. But there will be other drivers that are, so I accept this argument.

Yes, along these lines. There are many details to consider, and whoever designed the Klipper protocol should really be given a chance to tout its advantages as well :wink:
But unless we want to get into a deep discussion on protocol design, and without knowing the design goals the Klipper people had in mind, then I think its better to focus on the meat of the problem, and see what actually needs to be done…

I kind of already discussed this with @Juan-Antonio_Soren_E , and unfortunately my time hasn’t become more abundant. I’m happy to chat about it a bit, and happy to provide some guidance to get someone started, but I don’t feel I have the time to really do this effort - it will be a bit larger software project, and I won’t get it done in reasonable time.

1 Like

The brake_resistor road map / development is already a huge contribution in that regard. In due time it will all come together.

The potential is real world automation and productivity, like industrial laser-cutters, CNCs, so on and so forth.

sounds reasonable.

Klipper’s intent was to be able to separate the high-level work (gcode interpretation, motion planning, kinematics computation) that is most effectively done on a 64bit processor with lots of ram that’s running a non-realtime OS from the bit-banging that requires precise timing and where interruptions cause errors, allowing for much faster and accurate pulse generation to the stepper motor controllers, even using ancient 8 bit processors. Their protocol is built around this split in an all stepper world.

They are just starting to acknowledge that there is a world beyond that, and since most servo implementations can simulate stepper drivers (the step/dir interface), they are able to stick their heads in the sand and pretend that everything is good

so, @Juan-Antonio_Soren_E to talk implementation details.

There are three parts that I see

  1. the communication with klipper to receive the info
  2. convert the ‘execute X steps with timing Y in direction Z’ instructions that we will get from klipper into movement commands that make sense from simpleFOC
  3. execute the converted commands at the right time (since klipper sends the commands ahead of time for the MCU to queue so that it never stalls waiting to get the next movement)

The first seems reasonably straightforward to me (just a lot of digging through code to pull out the right info from klipper)
I don’t know enough about simpleFOC to even start on the other two steps.

1 Like

Right, as @Antun_Skuric has pointed out, derivs_limiter could be the bridge between SFOC and the Klipper commands. Look here:

That thread talks about the need for motion planning, instead of just changing the desired position. That should be less of an issue with klipper integration, because klipper is doing the motion planning, including acceleration planning and limits.

The problem is that instead of giving us that info, it’s giving us the step pattern to implement the resulting movement and we need to derive position, speed, and acceleration from what it’s providing. We are better off than step/direction in that we get this info ahead of time, rather than having to just chase the position the way step/dir does

I can understand the math to derive these from the info that klipper provides, but what’s the best way to have simplefoc know what is intended?

In an ideal world, what we want is a ‘at time T1 you should be at position P1 speed S1, move to position P2, accelerating at A2 to speed S2, which should take you to time T2’ followed by ‘at time T2 you should be at position P2 going speed S2, move to position P3, accelerating at A3 to speed S3 which should take you to time T3’, etc.
with the most important points being hitting the position and time (and should raise a flag if it deviates too much from the acceleration/speed requests. I believe that the acceleration is all going to be at a constant (max configured) rate
Since klipper is doing trapezoidal movement planning, we should be able to reverse engineer this and get acceleration sections and constant speed sections.
per that thread, it sounds like the acceleration data won’t be used by simpleFOC right now.

Hmm, I think you are on to something. I must say, my focus has been the PCB for a long time, but I’m eager to get down and nitty gritty with the code.

The Klipper kommands are in fact looking ahead, like you point out. Integrating the time factor is the challenge. Something MCUs are really good at, while human brains are like hot-wired for eternity/timeless states of mind. Anyways, I think you are right about the targets, buffering the commands and executing the actual movement. Based on speed?

Maybe we can have T1, T2, T3 be separate independent functions, extrapolating time in a sense. T1 = 10 milliseconds to now. T2 = 100 milliseconds to now, etc. pinpointing the datapoints, in the future so to speak. Always ahead of now, unpacking the relevant information.

Based on position and speed, deriving the needed torque or power-demand to execute the will of the maker

Acceleration is just a fancy word for going faster or slowing down. Its nice to have, so don’t discard it

re-reading the thread that you pointed me at, the solutions was to define a bunch of time/position pairs and order simpleFOC to move between them.

We can do that trivially, it’s just the step/direction interface with a queue instead of interrupt driven pin responses. But that is again throwing away the intent.

I believe that klipper will have two sorts of intents

  1. near constant speed S, but get to position P at time T
  2. adjust speed to near speed S (in as linear a ramp as you can reasonably do) but get to position P at time T

currently, in position mode we have ‘get to position P but don’t dare to go any faster than speed S and don’t apply any more power than X’ without any consideration of T. So it sounds as if we are going to need another command or two that let us define the movement in terms of time and the desired velocity ramp (as opposed to a torque limit)

then under the covers we can have the pid loops target this, very similar to what we have today, but where the speed and acceleration are strong suggestions, not hard limits (you can violate acceleration to make the speed target, and you can violate the speed target to hit the position on time). It may be that the speed and acceleration are less targets than monitoring settings, ‘warn if you vary from these too much’

does simpleFOC have a simulator mode where you can program in a motor and then run against that, plotting the expected response?

@runger can you see a better interface to use to pass the intent

I think you are on to something. The synchronization between the “master” Klipper processor is self-explanatory essential. That is the beat to which the whole thing works. In the Klipper protocol there is a way of doing that. So that should give us a now synced between all sub-MCUs. The really interesting stuff is the ramp I agree. In other words the ramp is the movement to hit the target position in time. If the force to uphold the ramp is somehow shortcoming, the control “algorithm” will apply more torque (up to a limit).

One thing to consider in that regard, now we are at the subject, does it make sense to use another profile then trapezoid, perhaps S-shaped

This I guess is what you mean by tweaking higher level motion planing, under the hood stuff

I have mentioned this before, but because it may proof to be a good source for inspiration, Mark from the OpenPNP community worked on S-curve motion for PNPs. Not sure how exactly, just pinning this :pushpin:

since klipper is doing the planning, and it does trapezoidal moves, that’s that we should plan to implement. I could see us ALSO wanting to implement s-curve moves for other systems, so we should probably consider it when designing new interfaces (for robotics or other less ridged machines, S curves would be a big advantage)

the drawback to s-curves is that it’s a lot more processing to coordinate multiple axis doing complex movements.

It’s common for 3d printers to be able to specify the jerk (derivative of acceleration) and the planner uses that as a limit to the acceleration, but most tend to do that as a series of trapezoids, not as a clean curve.

soapbox = on
I will note that s-curves are really a servo thing, not a stepper thing. with traditional stepper drivers you just have steps and the motor tries to stop after each step. It’s only with FOC on steppers or with servos that talking about acceleration/deceleration and it’s derivative force make sense as you are not dealing with hardware designed for continuous movement.

industrial processes move slowly, CNC machines have not finished the transition from expecting the operator to manually punch in g-code on a big panel at the machine.

3d printing has gotten CNC out into a much bigger world, and driven prices of light CNC brains, drivers, motors, rails, software down and in the process has wildly extended the number of people who understand it and places that it’s used. But it has been based on simple steppers for the most part (with some higher-end machines having ‘servos’ that are mostly steppers with encoders to detect missed steps)

a lot of CAM software (and a lot of gcode interpreters) don’t implement the more complex gcode, they just do linear moves and assume that there is no limit to acceleration (let alone force). They get away with this as the machines are generally light enough and flex enough to absorb the shocks.

but people are now noticing the effects of this in their 3d prints, and as the size, weight, and power of machines increase, these issues are harder to ignore
soapbox = off

Hi @davidelang

Im getting close to the talking to klipper point. Where should we start ?

This is running with the CORDIC for sine/cosine calculations. Using the float, so not ideal regarding loop speed and conversion time.

Running 24v from a regular 15A PSU. The motor and controller is completely cool. Im curios to see how this current sense for steppers turns out?

1 Like

@Antun_Skuric

What is this feed_forward story?

Do you think it can direct_drive a 8mm per rotation screw ? 16bit hardware encoder is 65536 ticks per rotation. 8mm / 65536 = 0,000122mm.

I do have the angle control working. Would you just send the angles, and try to achieve those angle as best as possible within the tuning parameters?

This was the TMC2660 drivers on the AZTEEG GT5

What about using easing functions to define the rate of change of position:

There loads of different easing functions that are all mathematically described so could form part of a command. You wouldn’t need to implement them all at once

Ok, right, its about the ramp.

But what if it had current control, then it could also scale the torque based on current reading. That, and the velocity, can be quite powerful hooks for controlling the speed. Maybe the mainframe should have control of some of the core functions.

Something to consider is how the USB should be used. It has several modes.

Not sure if this is useful for this thread but just in case here there is a trapezoidal planner that can be used on top of SimpleFOC to obtain smother movements.

It can be used as a base to implement other profiles of movements like S-Curves.

1 Like

Klipper is in a sense a parsing regime, based on USB (up to 64byte transfers); Source

Message Blocks

All data sent from host to micro-controller and vice-versa are contained in “message blocks”. A message block has a two byte header and a three byte trailer. The format of a message block is:

<1 byte length><1 byte sequence><n-byte content><2 byte crc><1 byte sync>

The length byte contains the number of bytes in the message block including the header and trailer bytes (thus the minimum message length is 5 bytes). The maximum message block length is currently 64 bytes. The sequence byte contains a 4 bit sequence number in the low-order bits and the high-order bits always contain 0x10 (the high-order bits are reserved for future use). The content bytes contain arbitrary data and its format is described in the following section. The crc bytes contain a 16bit CCITT CRC of the message block including the header bytes but excluding the trailer bytes. The sync byte is 0x7e.

The format of the message block is inspired by HDLC message frames. Like in HDLC, the message block may optionally contain an additional sync character at the start of the block. Unlike in HDLC, a sync character is not exclusive to the framing and may be present in the message block content.

@JorgeMaker

Here is the STM32 USB init from Klipper. Do you think it can be fitted to PlatformIO?

klipper/usbfs.c at master · Klipper3d/klipper (github.com)

First thing to do is to establish the connection. Then we can look at commands and what they should and should not do.

klipper/command.c at master · Klipper3d/klipper (github.com)

Im thinking the look ahead feature should handle incoming commands in stages with the primary handle being now();.

In that regard velocity is important. TODO: setup timer as velocity reference to encoder pulses.

From what I remember, from the last time going through the Klipper concept, it sends commands tied to a timestamp or time reference. It can do that, since all the sub_drivers or nodes, are synchronized to the mainframe running Klipper on a Pi or PC/Laptop. It also sends what stage in the Trapezoidal move the command is in e.g. accelerating, cruising, de-accelerating.

So, in the context of SFOC we have a command wanting to hit a specific velocity at a specific time. We also know if the next command in line is accelerating, just cruising (same speed) or if it is de-accelerating. Those commands will be coming in really fast with sub millimeter intervals.

Regarding the current sense in all this. The current sense will ensure stable torque control, since we constantly measure the current draw, related to torque.

I guess I will need a hardware serial connection to debug the USB transfers…

I imagine these commands will be parsed into a single or various circular buffers.

When doing the motion planning we then look at the move/command being performed now, the next command in line, and to give us some time-to-react we look at the buffer[10] or the 10th command in line, mainly to check whether the trapezoid state (accel/cruise/de-accel) will change in the foreseeable future. If the motor is sagging behind the commands (this all happens really fast) the controller will apply more current/torque, until a certain limit. Position in time, not to forget will tie the whole apparatus together

This is the link to our beloved Gcode. A.k.a. adaptive clearing.

You can develop an interpreter of Klipper commands making possible to run Klipper on the same microcontroller that you are using for your SimpleFOC instance, effectively creating a “Klipper Node.”
However, in my opinion, this is not in line with the purpose of SimpleFOC, as it operates at a higher layer. If you look at examples such as oDrive, VESC, or Moteus, none of them go beyond basic motion planning for a single axis.

@JorgeMaker lets move this to the proper thread. @Owen_Williams sorry for hijacking.

Ok, so because others do not facilitate multi-axis synchronized motion, SimpleFOC shouldn’t either?

Klipper is essentially a really well written fully functional USB parser, which interpret Gcode and handle all the timings, synchronization etc. what we have to do is teach SFOC how to talk Klipper or maybe even tinker with the mainframe …