Field Oriented Control (FOC) has revolutionized how we control BLDC motors, offering smooth operation and precise control that was once limited to expensive industrial systems. Thanks to the SimpleFOC library, implementing advanced motor control on Arduino has become accessible to makers, students, and engineers worldwide. This comprehensive tutorial will guide you through everything you need to know about using SimpleFOC on Arduino.
What is SimpleFOC?
Arduino Simple Field Oriented Control (FOC) project documentation aims to demystify FOC algorithm and make a robust but simple Arduino library: Arduino SimpleFOClibrary. The library supports as many motor + sensor + driver + mcu combinations out there, making it incredibly versatile for various applications.
SimpleFOC transforms complex motor control algorithms into simple, easy-to-use Arduino code. Instead of dealing with complicated mathematical transformations and PWM calculations, you can control BLDC motors with just a few lines of code.
Why Choose SimpleFOC for Your Projects?
Key Advantages
Cross-Platform Compatibility: Library supports Arduino devices such as Arduino UNO, MEGA, NANO and similar, stm32 boards such as Nucleo and Bluepill, ESP32 and Teensy boards.
Modular Design: The library supports multiple combinations of motors, sensors, and drivers, allowing you to mix and match components based on your project requirements.
Community-Driven: With over 50 contributors and an active community, SimpleFOC continues to evolve with regular updates and improvements.
Educational Value: The library is designed to teach FOC concepts while providing practical implementation examples.
Hardware Requirements
Essential Components
-
Arduino Board: UNO, MEGA, Nano, ESP32, or any supported microcontroller
-
BLDC Motor: Gimbal motors work well for beginners (internal resistance >10Ω)
-
Motor Driver: 3-phase PWM driver (like SimpleFOCShield or compatible boards)
-
Position Sensor: Encoder, magnetic sensor (AS5600, AS5047), or Hall sensors
-
Power Supply: Appropriate voltage for your motor (typically 12V)
Recommended Starter Kit
For beginners, the SimpleFOCShield provides an excellent starting point. This is an open-source low-cost Brushless DC (BLDC) motor driver board intended primarily for low-power FOC applications up to 5Amps. The board is fully compatible with the Arduino UNO and all the boards with the standard Arduino headers.
Installation and Setup
Installing the Library
The simplest installation method uses Arduino IDE's Library Manager:
-
Open Arduino IDE
-
Navigate to Tools > Manage Libraries
-
Search for "Simple FOC"
-
Install both "Simple FOC" and "Simple FOC drivers" libraries
-
Restart Arduino IDE
Alternative Installation
Click first on Clone or Download > Download ZIP. Unzip it and place it in Arduino Libraries folder. Windows: Documents > Arduino > libraries. Reopen Arduino IDE and you should have the library examples in File > Examples > Simple FOC.
Basic Code Structure
Every SimpleFOC project follows a consistent structure. Let's break down the essential components:
1. Library Include and Object Declaration
cpp
#include <SimpleFOC.h>
// BLDC motor instance - 11 pole pairs
BLDCMotor motor = BLDCMotor(11);
// Driver instance - pins 9,10,11 for PWM, pin 8 for enable
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 8);
// Encoder instance - pins 2,3 for channels A,B, 2048 PPR
Encoder encoder = Encoder(2, 3, 2048);
2. Interrupt Callbacks
cpp
// Encoder interrupt callbacks
void doA() { encoder.handleA(); }
void doB() { encoder.handleB(); }
3. Setup Function
cpp
void setup() {
// Initialize encoder
encoder.init();
encoder.enableInterrupts(doA, doB);
// Link sensor to motor
motor.linkSensor(&encoder);
// Configure driver
driver.voltage_power_supply = 12;
driver.init();
// Link driver to motor
motor.linkDriver(&driver);
// Set control mode
motor.controller = MotionControlType::velocity;
// Initialize motor
motor.init();
motor.initFOC();
}
4. Main Loop
cpp
void loop() {
// FOC algorithm execution
motor.loopFOC();
// Motion control
motor.move(target_velocity);
}
Step-by-Step Tutorial: Velocity Control
Let's create a complete velocity control example:
Complete Code Example
This is a simple Arduino code example implementing the velocity control program of a BLDC motor with encoder. NOTE: This program uses all the default control parameters:
cpp
#include <SimpleFOC.h>
// BLDC motor (11 pole pairs)
BLDCMotor motor = BLDCMotor(11);
// BLDC driver (pins 9,10,11 for PWM, pin 8 for enable)
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 10, 11, 8);
// Encoder (pins 2,3 for A,B channels, 2048 counts per revolution)
Encoder encoder = Encoder(2, 3, 2048);
// Interrupt callbacks
void doA() { encoder.handleA(); }
void doB() { encoder.handleB(); }
void setup() {
// Initialize serial communication
Serial.begin(115200);
// Initialize encoder hardware
encoder.init();
encoder.enableInterrupts(doA, doB);
// Link sensor to motor
motor.linkSensor(&encoder);
// Driver configuration
driver.voltage_power_supply = 12; // 12V power supply
driver.init();
// Link driver to motor
motor.linkDriver(&driver);
// Set control loop type
motor.controller = MotionControlType::velocity;
// Initialize motor
motor.init();
// Align encoder and start FOC
motor.initFOC();
Serial.println("Motor ready!");
}
void loop() {
// FOC algorithm execution
motor.loopFOC();
// Set target velocity (2 rad/s)
motor.move(2);
}
Understanding the Code
Motor Declaration: BLDCMotor(11) creates a motor object with 11 pole pairs. This parameter is crucial and must match your motor specifications.
Driver Setup: BLDCDriver3PWM(9, 10, 11, 8) defines PWM pins for the three motor phases and an optional enable pin.
Encoder Configuration: Encoder(2, 3, 2048) sets up an encoder with A/B channels on pins 2 and 3, with 2048 pulses per revolution.
FOC Execution: motor.loopFOC() must be called as frequently as possible (>1kHz recommended) for smooth operation.
Advanced Features and Control Modes
Position Control
For precise position control, modify the controller type:
cpp
motor.controller = MotionControlType::angle;
// Configure position PID controller
motor.P_angle.P = 20; // Position P gain
motor.PID_velocity.P = 0.2; // Velocity P gain
motor.PID_velocity.I = 20; // Velocity I gain
motor.velocity_limit = 4; // Maximum velocity limit
Torque Control
For direct torque control:
cpp
motor.controller = MotionControlType::torque;
motor.move(target_torque); // Set target torque in Nm
Adding Serial Communication
Here is the full code example with some additional configuration. Please go through the code to better understand how to integrate all previously introduced parts into one:
cpp
#include <SimpleFOC.h>
// Motor, driver, and sensor instances
BLDCMotor motor = BLDCMotor(11);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
MagneticSensorSPI sensor = MagneticSensorSPI(AS5147_SPI, 10);
// Commander interface for serial control
Commander command = Commander(Serial);
void doMotor(char* cmd) { command.motor(&motor, cmd); }
void setup() {
Serial.begin(115200);
// Initialize sensor
sensor.init();
motor.linkSensor(&sensor);
// Initialize driver
driver.voltage_power_supply = 12;
driver.init();
motor.linkDriver(&driver);
// Motor configuration
motor.controller = MotionControlType::velocity;
motor.init();
motor.initFOC();
// Add commander interface
command.add('M', doMotor, "motor commands");
Serial.println("Motor ready!");
Serial.println("Send 'M' followed by command:");
Serial.println("- MV5 (velocity 5 rad/s)");
Serial.println("- MA1.57 (angle 1.57 rad)");
}
void loop() {
motor.loopFOC();
motor.move(); // Use commander target
command.run(); // Process serial commands
}
Sensor Configuration Options
Magnetic Sensors (I2C)
cpp
// AS5600 magnetic sensor
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
void setup() {
Wire.setClock(400000); // Set I2C speed
sensor.init();
// ... rest of setup
}
Hall Sensors
cpp
// Hall sensor on pins 2, 3, 4 with 11 pole pairs
HallSensor sensor = HallSensor(2, 3, 4, 11);
// Interrupt callbacks
void doA() { sensor.handleA(); }
void doB() { sensor.handleB(); }
void doC() { sensor.handleC(); }
void setup() {
sensor.init();
sensor.enableInterrupts(doA, doB, doC);
// ... rest of setup
}
Troubleshooting Common Issues
Motor Not Rotating Smoothly
-
Check pole pairs: Ensure the motor pole pair count is correct
-
Verify sensor direction: The sensor and motor rotation should be synchronized
-
Power supply: Ensure adequate power supply capacity
-
Wiring: Double-check all connections
Sensor Reading Issues
The first sign that tells us that everything is well connected is if the sensor readings are good. To test the sensor please browse the library examples examples/utils/sensor_test and find the example for your sensor.
Test your sensor independently:
cpp
#include <SimpleFOC.h>
Encoder encoder = Encoder(2, 3, 2048);
void doA() { encoder.handleA(); }
void doB() { encoder.handleB(); }
void setup() {
Serial.begin(115200);
encoder.init();
encoder.enableInterrupts(doA, doB);
}
void loop() {
encoder.update();
Serial.print("Angle: ");
Serial.print(encoder.getAngle());
Serial.print("\tVelocity: ");
Serial.println(encoder.getVelocity());
delay(100);
}
Performance Optimization
-
Increase loop frequency: Ensure motor.loopFOC() runs at >1kHz
-
Disable serial monitoring: Remove motor.monitor() calls for production code
-
Optimize sensor updates: Use hardware interrupts for encoders
Project Ideas and Applications
Beginner Projects
-
Camera gimbal stabilization
-
Precision positioning system
-
Speed-controlled fans
-
Educational FOC demonstration
Advanced Applications
-
Robotic joint control
-
CNC spindle motors
-
Drone propeller control
-
Electric vehicle motor control
Best Practices and Tips
Code Organization
-
Always initialize components in the correct order: sensor → driver → motor
-
Use meaningful variable names for different motors in multi-motor projects
-
Implement proper error handling for initialization failures
Hardware Considerations
-
Use proper decoupling capacitors on power supplies
-
Keep sensor wiring away from high-current motor wires
-
Ensure adequate cooling for motor drivers
-
Use twisted pair cables for encoder signals
Performance Tuning
-
Start with default PID parameters and adjust gradually
-
Monitor motor current and temperature during testing
-
Use oscilloscope to verify PWM signals if available
Conclusion
SimpleFOC transforms complex motor control into accessible Arduino programming, opening up advanced BLDC motor control to makers and engineers worldwide. Whether you're building a camera gimbal, robotic system, or learning about motor control theory, SimpleFOC provides the tools and community support needed for success.
The library's modular design means you can start simple and gradually add complexity as your projects evolve. With comprehensive documentation, active community support, and continuous development, SimpleFOC represents the future of open-source motor control.
Start with basic velocity control, experiment with different sensors and motors, and join the growing community of FOC enthusiasts pushing the boundaries of what's possible with Arduino-based motor control.
Frequently Asked Questions
1. What motors work best with SimpleFOC for beginners?
Gimbal motors with internal resistance greater than 10Ω are ideal for beginners. They're designed for low-speed, high-precision applications and typically have 11 or 14 pole pairs. Popular choices include the GM4108 and similar brushless gimbal motors.
2. Can I use SimpleFOC without position sensors?
Yes, SimpleFOC supports open-loop control without sensors, though you'll lose precision and smoothness. For optimal FOC performance, position feedback from encoders, magnetic sensors, or Hall sensors is recommended for closed-loop control.
3. How do I determine the correct pole pair count for my motor?
Count the permanent magnets on the rotor and divide by 2, or check motor specifications. If the motor vibrates or doesn't rotate smoothly, the pole pair count is likely incorrect. Most gimbal motors have 11 or 14 pole pairs.
4. What's the difference between SimpleFOC and traditional ESCs?
Traditional ESCs use six-step commutation for high-speed applications, while SimpleFOC uses sinusoidal Field Oriented Control for smooth, precise control at all speeds. SimpleFOC excels in positioning and robotics applications.
5. Why does my motor get hot during operation?
Motor heating indicates excessive current draw from incorrect parameters, insufficient power supply, or wrong pole pair settings. Check voltage limits, motor mounting, and pole pair count. Consider adding current sensing for better control.