On this page
Writing Your Motor Control Code
Ready to write SimpleFOClibrary code? This page is your reference guide to understanding how the library works and how to structure your motor control applications.
📚 Before You Start
Choose your path based on your experience level:
| Your Situation | Recommended Starting Point | Link |
|---|---|---|
| First time with SimpleFOC? | Use this page as a reference to understand all components and their configuration options | Start here |
| Already have the hardware and you want to get started quickly? | Follow the step-by-step guide to get your motor running as quickly as possible | Getting Started |
| Building from existing code? | Jump to the specific section you need below and follow the links to detailed documentation | Jump to here |
| Want to understand the theory and library implementation details? | Check out the detailed documentation for each component and control strategy | Digging Deeper |
Quick Setup Overview
See how to build a complete motor control application step-by-step. Click through each tab to see the code build incrementally:
Sensor +Driver +Current Sense +Motor +Real-time Loop +User Interface
#include <SimpleFOC.h>
// 1️⃣ SENSOR
Encoder sensor = Encoder(2, 3, 2048);
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void setup() {
sensor.init();
sensor.enableInterrupts(doA, doB);
}
void loop() {
sensor.update();
}
Core Components Reference
Position Sensors
Initialize and configure your position sensor. The motor cannot be controlled without knowing its current angle.
The library supports four sensor types:
- Encoders: Optical, Capacitive, Magnetic encoders (ABI)
- Magnetic sensors: SPI, I2C, Analog or PWM
- Hall sensors: 3xHall sensing, Magnetic sensor (UVW interface)
- Generic sensors NEW📢: A simplified sensor implementation for adding custom sensors
Choose a position sensor to use with this example:
Encoder Magnetic sensor Hall sensors
#include <SimpleFOC.h>
// Encoder(pin_A, pin_B, PPR)
Encoder sensor = Encoder(2, 3, 2048);
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void setup() {
// initialize encoder hardware
sensor.init();
// hardware interrupt enable
sensor.enableInterrupts(doA, doB);
}
void loop() {
}
Encoders as position sensors are implemented in the class Encoder and are defined by its:
AandBchannel pin numbers:2and3- Encoder
PPR(impulses per revolution number):2048 Indexpin number (optional)
Initialize the hardware pins by running sensor.init().
For full documentation of the setup and all configuration parameters please visit the position sensors docs .
Motor Drivers
Initialize the motor driver. This component translates motor control commands into PWM signals for your motor phases.
BLDC Driver - 3PWM Stepper Driver 4PWM
BLDCDriver3PWM class is instantiated by providing:
- pwm pins for phases
A,BandC enablepin number (optional)
For example:
#include <SimpleFOC.h>
// BLDCDriver3PWM( pin_pwmA, pin_pwmB, pin_pwmC, enable (optional))
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// instantiate sensor
void setup() {
// init sensor
// pwm frequency to be used [Hz]
driver.pwm_frequency = 20000;
// power supply voltage [V]
driver.voltage_power_supply = 12;
// Max DC voltage allowed - default voltage_power_supply
driver.voltage_limit = 12;
// driver init
driver.init();
}
void loop() {
}
For full documentation of the setup and all configuration parameters please visit the driver docs .
Current Sensing (Optional)
Current sensing enables true field-oriented control (FOC) with closed-loop current feedback. You can skip this if your setup doesn’t include current sense hardware.
The library supports two current sense architectures:
In-line current sensing Low side current sensing
InlineCurrentSense class is instantiated by providing:
- shunt resistor value
shunt_resistance - amplifier gain
gain - analog pin numbers for phases
A,B(and optionallyC)
For example:
#include <SimpleFOC.h>
// instantiate driver
// instantiate sensor
// InlineCurrentSense(shunt_resistance, gain, adc_a, adc_b)
InlineCurrentSense current_sense = InlineCurrentSense(0.01, 50, A0, A2);
void setup() {
// init sensor
// init driver
// link the driver with the current sense
current_sense.linkDriver(&driver);
// init current sense
current_sense.init();
}
void loop() {
}
For full documentation of the setup and all configuration parameters please visit the current sense docs .
Motor Instance
Create and configure your motor instance. Link it with the sensor and driver you’ve already initialized.
The library supports three motor types:
BLDC motor Stepper motor HybridStepper motor
In this example we will use BLDC motor:
#include <SimpleFOC.h>
// BLDCMotor( pole_pairs , ( phase_resistance, KV_rating optional) )
BLDCMotor motor = BLDCMotor(11, 9.75);
// instantiate driver
// instantiate sensor
// instantiate current sensor
void setup() {
// init sensor
// link the motor to the sensor
motor.linkSensor(&sensor);
// init driver
// link the motor to the driver
motor.linkDriver(&driver);
// link driver and the current sense
// link the motor to current sense
motor.linkCurrentSense(¤t_sense);
// set control loop type to be used
motor.controller = MotionControlType::velocity;
// initialize motor
motor.init();
// init current sense
}
void loop() {
}
After the instance of the motor motor has been created we need to link the motor with the sensor motor.linkSensor() and link the motor class to the driver it is connected to motor.linkDriver().
The next step is the configuration step, for the sake of this example we will configure only the motion control loop we will be using:
// set control loop type to be used
motor.controller = MotionControlType::velocity;
And to finish the motor setup we run the motor.init() function.
For full documentation of the setup and all configuration parameters please visit the motor docs .
FOC Initialization & Motion Control Loop
Align the motor/sensor and run the real-time control loop. This is where the FOC algorithm executes.
motor.loopFOC(): FOC algorithm execution - should be executed as fast as possible> 1kHzmotor.move(target): motion control routine - depends on themotor.controllerparameter
Here is how it looks in code:
#include <SimpleFOC.h>
// instantiate motor
// instantiate driver
// instantiate sensor
// instantiate current sensor
void setup() {
// init sensor
// link motor and sensor
// init driver
// link motor and driver
// link driver and the current sense
// link motor and current sense
// configure motor
// init motor
// init current sense
// align encoder and start FOC
motor.initFOC();
}
void loop() {
// FOC algorithm function
motor.loopFOC();
// velocity control loop function
// setting the target velocity to 2rad/s
motor.move(2);
}
For full documentation of the setup and all configuration parameters for BLDC motors please visit the BLDCMotor docs , and for Stepper motors please visit the StepperMotor docs
Optional Features
Monitoring
BLDCMotor and StepperMotor classes provide monitoring functionality. For enabling the monitoring feature make sure you call motor.useMonitoring() with the Serial port instance you want to output to. It uses Serial class to output motor initialization status during the motor.init() function, as well as in motor.initFOC() function.
If you are interested in outputting motors state variables in real-time (even though it will impact the performance - writing the Serial port is slow!) add the motor.monitor() function call to the Arduino loop() function.
#include <SimpleFOC.h>
// instantiate motor
// instantiate driver
// instantiate senor
void setup() {
// init the serial port
Serial.begin(115200);
// init sensor
// link motor and sensor
// init driver
// link motor and driver
// link driver and the current sense
// init current sense
// link motor and current sense
// use monitoring with the BLDCMotor
Serial.begin(115200);
// monitoring port
motor.useMonitoring(Serial);
// configure motor
// init motor
// init current sense
// align encoder and start FOC
}
void loop() {
// FOC execution
// motion control loop
// monitoring function outputting motor variables to the serial terminal
motor.monitor();
}
For more docs on the BLDCMotor and StepperMotor monitoring see the Monitoring docs.
Debugging Output
SimpleFOClibrary provides an informative debugging interface that can be enabled by calling SimpleFOCDebug::enable(&Serial) function. This function enables the debugging output of the library to the Serial port. This debugging interface will output a more detailed information about:
- driver initialization (during the
driver.init()function) - current sense initialization (during the
current_sense.init()function) - motor initialization (during the
motor.init()function) - motor FOC initialization (during the
motor.initFOC()function)
The debugging output will provide more information about the state of the motor, driver and current sense during and after the initialization process and will help you to debug your setup. It will also provide MCU architecture specific information such as which Timers and channels are used for PWM generation, which ADC is used for current sensing, did the TIME-ADC synchronisation work, etc.
📢 We strongly advise to use the debugging mode when starting with the SimpleFOClibrary. It provides much more information than the standard monitoring output and can help troubleshooting potentially problems, even MCU architecture specific ones.
Memory usage
Debugging outputs are strings which can take a considerable amount of memory space, so it's not recommended to use it in the final application.
Debugging output is disabled by default and can be enabled by calling the SimpleFOCDebug::enable(&Serial) function before any of the driver, sensor, current_sense or motor initalisation (init calls). Preferably put the SimpleFOCDebug::enable(&Serial) function call at the beginning of the setup() function.
#include <SimpleFOC.h>
// instantiate motor
// instantiate driver
// instantiate senor
void setup() {
// init the serial port
// enable the debugging output
SimpleFOCDebug::enable(&Serial);
// init sensor
// link motor and sensor
// init driver
// link motor and driver
// link driver and the current sense
// init current sense
// link motor and current sense
// enable monitoring
// configure motor
// init motor
// init current sense
// align encoder and start FOC
}
void loop() {
// FOC execution
// motion control loop
// monitor variables
}
For more docs on the debugging capabilities of the SimpleFOClibrary see the Debugging docs.
Commander Interface
Finally, in order to configure the control algorithm, set the target values and get the state variables in the user-friendly way, (not just dumping as when using motor.monitor()) SimpleFOClibrary provides you with a g-code like communication interface in form of the Commander class.
Full motor commander Only motor target value Motion control target + Led control
The following code is one basic implementations of the full communication interface with the user:
#include <SimpleFOC.h>
// instantiate motor
// instantiate senor
//instantiate commander
Commander commander = Commander(Serial);
void doMotor(char* cmd){commander.motor(&motor, cmd);}
void setup() {
// init the serial port
// enable the debugging output
// init sensor
// link motor and sensor
// init driver
// link motor and driver
// link driver and the current sense
// init current sense
// link motor and current sense
// enable monitoring
// subscribe motor to the commands
commander.add('M',doMotor,"motor");
// init motor
// init current sense
// align encoder and start FOC
}
void loop() {
// FOC execution
// motion control loop
// monitor variables
// read user commands
commander.run();
}
For full documentation of the setup and all configuration parameters please visit the Communication docs.
Next Steps & Resources
Hands-on Learning
Ready to test your setup? Work through the complete step-by-step guide with testing procedures, troubleshooting, and hardware validation:
📖 Getting Started: Step-by-Step Walkthrough
Reference & Configuration Guide
Once your motor is running, you can optimize and extend it:
| Feature | Purpose | Documentation |
|---|---|---|
| Sensors | Support for encoders, magnetic sensors, hall sensors, and generic sensors | Position Sensors |
| Drivers | Support for various BLDC and stepper drivers | Motor Drivers |
| Current Sensing | In-line and low-side current sensing options | Current Sensing |
| Motors | Support for BLDC, stepper, and hybrid stepper motors | Motors |
| Motion Controllers | Change between velocity, angle, torque modes | Motion Control |
| Torque/FOC Controllers | Change between voltage and current modes | Torque/FOC Control |
| Communication | Real-time parameter adjustment via serial | Commander Interface |
| Debugging | Detailed initialization diagnostics | Debugging |
| Monitoring | Output real-time state variables | Monitoring |
Library Source Code
If you are interested in extending and adapting the SimpleFOClibrary source code you can find full documentation in the library source docs