Can I use the SimpleFOC library to drive syncronized axes in closed-loop?

Hello everyone!

I bring a question about synchronising motion between three or more motors, with the SimpleFOC library, in a cartesian robot.

From my shallow knowledge, I understand that this implies getting the robot to follow a certain “trajectory” as close as possible.

The problem seems a bit complex to tackle on my own, but this is what I would do with what I know:

  1. Setup 3 SimpleFOC position controls on a single MCU, connect 3 motors to it, and have the program wait for a target XYZ position.
  2. Split any incoming move (e.g. a G1 X1 Y1 Z1) into N small linear segments, starting at the current position and ending at the final position.
  3. Pass the segment’s X, Y, and Z values (and feedrates → velocity_limit) to their respective instances of position control: Position Control | Arduino-FOC
  4. Monitor the current position, and measure the error from the current position to the closest point on the current segment. If the end of the segment is near, pass the next target position values to the position controllers, else wait (or error out?).

I wonder about a few things here:

  1. Would setting motor_x.velocity_limit = feedrate_x actually do what I am assuming it would? (i.e. move as fast as possible while respecting the velocity limit).
  2. Would the robot actually follow the approach “closely enough” with this setup?
  3. What would be the resulting acceleration?

All thoughts appreciated!



Some illustration:


There is no MCU that supports three motors. Best you could do is 2, and that’s not advisable.

You need to have 3 MCUs driving the 3 motors, controlled by an external fourth MCU.

Then develop an external protocol to control the three MCUs.

Depending on the degree of control, speed and accuracy, for example a high accuracy CNC mill or an SMD Pick and Place machine, you may need an optical encoder on each motor, and/or high accuracy gearing to increase precision.

That’s a very ambitious project, please come back and report your findings.


Hi thanks for the quick reply!

Hmm I was afraid of this.

There is an interesting project from MIT I am tempted to try out: GitHub - modular-things/modular-things: plug and play w/ virtualized hardware

It’s called “Modular Things”. I like it but it does not sync the internal clocks of the MCUs yet.

Here is a CNC machine using it:

I’ll have to think about this further!

I’m lying to you just a little bit, there is actually ONE MCU that can run three motors in 6PWM, and there is a way to make one MCU run three motors in a 3PWM mode, but this is really advanced stuff since you also need to sensor the three motors and you also want the MCU to run custom logic inside the motor control loops, that’s bordering on 99-level wizardry of skills since you need to develop and fab also a custom 3-motor driver PCB.

At your level, better try small first.


1 Like

I seem to have a tendency towards finding hard problems quickly. xD

Thanks again!

If you really, I mean, REALLY want to go that route. You will need a custom board designed with STM32G474 for 6 PWM on a 100pin or higher footprint. I’m not sure the 474 has enough processing power to do everything though.

Or, you will need a board with three drivers working on a 3PWM output and then some pretty complex code inside running on one MCU, probably one of the 550 MHz STM32 H series.


Hmm I think that a more general/plug-and-play solution would be better. Someone will want one more axis, and the integrated solution would fall short in no time.

Besides, I’m not up to the task. :slight_smile: But anyway… I might just learn a bit while I’m here.

The ideal solution could involve a distributed system of modular axes that talk to each other for synchronisation and coordination (as you proposed). Two questions then:

  1. Are there good libraries for “daisy chaining” MCUs into a small network?
  2. Is there a library that can be used to keep the internal clocks of different MCUs in sync?

Klipper solves this by having a central “host” that somehow adjusts drifts in timing. But I have come to dislike the host requirement, and found it to be rather fragile (prone to timing errors and shutdowns).

I know that Modular Things (used in the Clank CNC machine) does not sync clocks yet. It could be a perfect fit otherwise. Not sure what protocol/medium it uses.

I am tempted to do something really simple for time syncrhonization (like this: How to sync two Arduino in microsecond - Stack Overflow) but I’d be missing the networking part (i.e. broadcasting messages from the PC to other modules). Could I2C or other protocol be good for that?

I’m not thinking about HTTP because I’ve tried using that with SimpleFOC on an ESP32 and it already caused issues. A lower level / faster medium seems better.


Doing 3 motors on a single MCU is indeed hard. When running the motors with FOC control, its not just a problem of interfacing all the motor drivers and sensors to the MCU, but also a problem of performance, since the FOC algorithm needs quite a few resources and is also time-critical.

But I do think you’re overthinking it slightly. If you want to give it a go, just get yourself 3 SimpleFOC setups using a simple MCU and a SimpleFOC mini for each motor, for example (or bigger drivers if you need more power). Get each one running to your satisfaction (e.g. tuning, safety features, etc).

Then, add a fourth MCU (or maybe a RPi) and start working on your control problem. That’s not easy, but there are plenty of resources to draw on for inspiration. There are several people here on the forum who have built robot arms with multiple motors, and might be willing to share their software or experience.

CAN bus is built into many MCUs, and non-isolated CAN-controllers/transcievers are pretty cheap. There is a SimpleCAN library done by one of our members here you could look at, as well as other CAN solutions.

But you could also just use 3 serial ports, many MCUs have 3 UARTs or on a RPi you can add as many as you need with USB2Serial converters.

You may also want to take a look at Klipper - which can already coordinate multiple motor MCUs and converts GCODE inputs into movement on the motors.

Note also if you don’t want to mess around with the motor control itself there are more finished motor drivers available you could use… take a look at the ODrive, Moteus and SOLO motor controllers… while I love SimpleFOC and motor control, if you’re actually just looking to move the robot rather than invent your own controller boards or mess with the FOC algorithms, then using a finished motor driver with turnkey software will be faster…

1 Like

Thanks a lot for the review! It cleared up the scenario for me.

I will certainly check it out, and dive a little deeper.

I’m interested in learning more about distributed control, precise timing, coordination, and modularity, and what components are available to build better hardware for lab automation. I see SimpleFOC as an excellent component.

Until I end that quest and decide to build a new robot, I’ll stick to the very boring NEMA17+A4988 combo.

Probably true! I’ll try to follow your advice and have some fun.

Certainly! Klipper comes close to the ideal in several ways, but there is a big catch driving me away from it.

I’ve learnt about the host part by trying to add 3 extra axes, but finally realized that Klipper really is just a 3D-printer firmware. It was never meant to be extended to other applications.

In my view, it always surprises how any use of Klipper beyond 3DP ends up encumbered by that fact.

Its design concepts are great though. That’s why I really like the Modular Things / Clank project (Tool Changer and Tools | Clank), which is only missing the clock synchronization part.

Could you please explain what’s so critical about clock synchronization? Why do you even need that?

Just send a message to motor 1, go to point M1 with speed S1, motor 2 go to point M2 with speed S2 and motor 3 go to point M3 with speed S3. We are talking points in motor space obviously.

If you need to so closely control the trajectory just make many very small steps.

What am I missing here? As @runger said you may be overthinking this. Unless you are running some ultra-fast lidar where the laser beam is being bounced between two mirrored motors and you need to perfectly synchronize the phases to measure the time of flight with literally light speed, controlling three motors synchronously to position a slowly moving robotic arm while syncing the motor clocks seems like a gross overkill.


For many applications, just sending the motor messages one by one, without coordinating them in time, will work fine, because the latency between commanding the different motors will be only a few milliseconds at most.
The idea of controlling in small steps can also be helpful for sure, to correct any errors due to inaccuracy that would otherwise occur if the motors moved longer distances.

But there will be applications, including 3D printing and CNC, where even millisecond differences will make a difference to the result (esp in CNC) and you really need to coordinate the motors synchronously. In this case using synchronised clocks and working with timestamps could be a solution to ensure the motors really move in sync.

1 Like

Sorry about it, there is more to my project than I’ve explained. Lab automation is in my bigger picture, which can involve timing of events with millisecond or microsecond precision (e.g. illumination and acquisition in a microscope), and closed-loop control is also important in a variety of scenarios.

This is very long term. I’d like to do this with open source components, and I really like SimpleFOC and its community.

Yesss looks like step one! to me :slight_smile:

pinging @Copper280z for their extremely interesting klipper-commander using simpleFOC :smiley:

1 Like

Yup, it’ll do that, I just haven’t sorted out the last little issues like the apparent clock drift. I got distracted getting the milk-v duo up and running bare metal C instead of linux. Klipper has inherent latency when sending commands from the host to a motor, because the mcu caches motion commands which the host has scheduled in the future. This is part of the clock sync thing it does.

The G474 has the processing power to run 3 motors if you’re willing to do some hacking within the library, and write very efficient IO code. (and you’ll need both!) You will need one of the big ones, it seems you can do 3 motors with 6pwm on a g474vet, but I really see no reason 6pwm is a big advantage over 3pwm. You’ll need to make sure the drivers configure correctly, but as there are enough timers to put each motor on a dedicated one it should be fine. If you really need tightly synchronized motion, I assume you’ll want it to be relatively high performance motion, so you’ll want current sensing, getting that up and running with 3 motors will be tricky for sure. You should plan on basically writing your own hardware driver that the current sense classes call into to get data from the hardware. The H7 is for sure a better choice, but you’ll definitely need to write your own drivers for it as I don’t think anyone else has.

Now tuning it all to get good control bandwidth and stability for microscopy is gonna be a project all on it’s own!

1 Like


Perhaps a stupid question.

Isn’t current sensing generic enough to run on H7 out of the box? What makes you conclude that?


Inline current sensing is, but low side current sensing is not. Inline as it’s implemented now is pretty undesirable because of how stm32duino does analogRead.

Stm32duino totally reconfigures the ADC and starts a conversion for every call. I don’t remember the exact rate I got testing this in a tight loop, but it’s pretty slow.

The sfoc low side stm32 driver uses hardware features to schedule the ADC conversions synchronized with the timers, so it takes no CPU time at all and it becomes trivial to sample multiple motors at 20-40khz each.

You say inline is just an analog read call?

That’s really, really slow. Now I get it.

Why can’t we do the same for inline, to mimic low side but inline, who cares at what point the measurement is taken?


You can just use the low side class with an inline sensor, it works fine.

Depending on the inline sensor it’s good to avoid reading close to one of the pwm edges because most shunt amplifiers, even the really good ones, ring for a bit on the voltage transitions. The magnetic sensors don’t have this problem.

1 Like

My experience with the klipper project is that if you want to do something that is in anyway outside of a very narrow band of functionality dictated by project owner, you will be met with hostility and condescension. I was afraid it was just me, but I’ve since heard a similar experience from many others.

You might be interested in discussing this with others who are working on their own 3d printer firmware. One project (in rust, but concepts should be language agnostic) is pronthor

1 Like