Future Request! SimpleFoc (Field Oriented Control) stepper strategy, not step/dir in time but movement in space and time

I was directed from Github to this forum…

How is the dev. on Field Oriented Controlled steppers in this community. Ive mainly been focused on SimpleFoc stuff lately and I do have experience with circuit board design. If there is interest for it, I might sketch up a S_FOC stepper driver. The general idea is to drive it without a mainboard, since each driver would be a “sub_driver” controlling the stepper directly through 4 halv-bridges (FETs). This requires an alternative strategy for Klipper / driver movement execution (not step/dir) and would have a great potential, especialy for CNC purposes with standard NEMA23 steppers running eg. 48v. (Closed loop).

While building a Cartesian CNC I was asking around in UGS repo about implementing a sub_driver encoder MCU for UGS side closed loop control (offset from Gcode path correction/validation) I was then prompted to investigate Klipper as a alternative route. So, now I’m asking this —> does it make sense to merge the Klipper concept with SimpleFoc advanced in FOC stepper control. Obviously it will not involve step/dir calculations but another strategy for reaching the same point in the space/time continuum

Link Sync Multi stepper CNC setup - #6 by Juan-Antonio_Soren_E - SimpleFOC Community

FYI, there has been some discussion on this in the past with the mechaduino support ( Mechaduino experiment ) and similar topics (eg, Experiment with hall effect angle sensors ).


I see, interesting, although no mention of Field Oriented Control.

Basically SimpleFoc is all about supporting as many angle sensors, MCUs etc. mainly for 3phase BLDC´s, but steppers are also a possibility. It would be quite cool to find a way to make Klipper and SimpleFoc interact. If the FOC stepper driver was to read the dir/step signals and store those in a buffer, it would still need a MCU to generate those signals. IMO a starting point could be to see how tight we can make a FOC stepper driver move with angle setpoints delivered by Klipper. I guess that is the actual question at hand. Can the Field Oriented Control be used to achieve the same accuracy in a timely manner as a typical dir/step interface or maybe better since its closed loop.

The Klipper concept can be a bit hard to grasp. How exactly are the timings done? with regards to timestamps / desired coordinates synced between sub_drivers.

From my basic understanding of Klipper its all done within the predefined acceleration, feedrate and de-acceleration. Those could most certainly be managed by a FOC driver.

Usually a 3D printer is defined by its physical format in mm. those millimeter are then divided into steps per millimeters and so the machine has its boundaries divided into the step/dir language in lag of a better word. What if that language was angles, like the way SimpleFoc talk.

I found this in the Klipper repo:

def units_in_radians(self):
`# Returns true if distances are in radians instead of millimeters
return self._units_in_radians


Regarding the buffer.

The usual stepper driver concept, like Marlin etc. has a buffer with moves which is then translated to step/dir. In the case of Klipper talking to SimpleFoc, I guess there needs to be a buffer as well for the FOC driver to have smoooth motion going on. I know there are some folks in the SimpleFoc community working on a planner of sorts or at least talking about it, just to say there is definitely interest in the matter.

Have been hard at work making a modular FOC stepper driver. The click-on sensor, is meant to be TM6835 with SPI transfers, possibly DMA. That MCU breakout_stack is the SAME51 (D51 just with CAN bus). I see you have support for the SAMD51.

The MCU could be stronger but I have faith in the SAME51. Maybe even dual core at some point.

Best regards

I’m not sure if you’ve seen the description at Code overview - Klipper documentation and in particular Code overview - Klipper documentation .

Briefly, moves are tracked in the “trapq” using mm, mm/s, and mm/s^2. The “iterative solver” then finds the appropriate clock time for every step. Finally, the “step compression” converts those step times into a series of quadratic equations (ie, queue_step commands containing interval, add, count). The mcu then produces the step pulses at the times in the given schedule. Be sure to read the documents above for the full description.

Using more advanced micro-controller control of the motor coils has been discussed several times in the past. (Both FOC and other approaches.) In particular, there has been interest in possibly using the desired carriage velocity and acceleration in determining the motor coil currents.

To summarize some previous discussions, there were two proposed approaches to doing the above - the first could be thought of as a “fixed frequency position/velocity/acceleration” system, and the second as “micro-controller derivatives of position change to obtain velocity/acceleration”. Roughly, the first involved changing the Klipper host to avoid the “iterative solver” and to provide the micro-controller with a list of position/velocity/acceleration tuples at a fixed frequency (eg, 5000 times a second). Roughly, the second would involve little change to the host and instead the micro-controller could inspect the existing queue_step commands to estimate the velocity/acceleration of the stepper (by observing the time difference between requested steps).

I don’t know of anyone who has done any notable work on the above. It was just discussions as far as I’m aware.

The mechaduino code I mentioned previously implements a bit of the second strategy - it takes the existing queue_step commands and determines the desired stepper position from them. A fixed frequency loop then alters the stepper motor coil current based on the desired position. The code was primitive however.

FYI, the latest Klipper code has support for SAME51 (and SAME54) chips, including canbus support.


From the little I know about the SAME51 USB interface, I know it has a build in DMA, so all traffic are more or less handled parallel to the main loop, depending on how the USB is setup. Are Klipper using USB packets or is it a serial-derivative ?

Ultimately it depends on how we parse the data into the code. Just because it is in a message form, still means we have to decipher it. That would take some processing power/time.

SimpleFOC has velocity control and torque control, it also has angle control. I believe the best chance of merging Klipper with SimpleFOC is a combination of the three.

On each FOC iteration, the controller then manages the torque, from predefined stepper tuning parameters, the torque needed to hold the target velocity in order to reach the desired angle in time.

FunQi FOC Stepper driver | Hackaday.io

Having torque control (current control) means we will know if the machine has crashed into some obstacle it can’t overcome, within a predefined limit.

Edit: I was just told, there is a stepdir_listener in SimpleFOC, but the other method is more appealing. Again, in that scenario we would need a MCU to produce the STEP/DIR pulses, which defeats the purpose, but I guess it would make it more convenient to link the Klipper step/dir generator with the SimpleFOC step/dir listener, although the code will look cleaner if the step/dir konversion was offloaded from the MCU.

Arduino-FOC/src/communication at master · simplefoc/Arduino-FOC (github.com)

This is some really sweet coding on the samd USB interface init
klipper/usbserial.c at master · Klipper3d/klipper (github.com) Pipe Configuration
Pipe data can be placed anywhere in the RAM. The USB controller accesses these pipes directly through the AHB
host (built-in DMA) with the help of the pipe descriptors. The base address of the pipe descriptors needs to be written
in the Descriptor Address register (DESCADD) by the user. Refer to Pipe Description Structure.
Before using a pipe, the user should configure the direction and type of the pipe in Type of Pipe field in the Host
Pipe Configuration register (PCFG.PTYPE). The pipe descriptor registers should be initialized to known values before
using the pipe, so that the USB controller does not read the random values from the RAM.
The Pipe Size field in the Packet Size register (PCKSIZE.SIZE) should be configured as per the size reported by the
device for the endpoint associated with this pipe. The Address of Data Buffer register (ADDR) should be set to the
data buffer used for pipe transfers.

Source Datasheet

It appears to be laid out for testing with this lib.