Free Shipping for orders over ₹999

support@thinkrobotics.com | +91 93183 94903

SimpleFOC on Arduino Tutorial: Complete Guide to BLDC Motor Control

SimpleFOC on Arduino Tutorial: Complete Guide to BLDC Motor Control


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

  1. Arduino Board: UNO, MEGA, Nano, ESP32, or any supported microcontroller

  2. BLDC Motor: Gimbal motors work well for beginners (internal resistance >10Ω)

  3. Motor Driver: 3-phase PWM driver (like SimpleFOCShield or compatible boards)

  4. Position Sensor: Encoder, magnetic sensor (AS5600, AS5047), or Hall sensors

  5. 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:

  1. Open Arduino IDE

  2. Navigate to Tools > Manage Libraries

  3. Search for "Simple FOC"

  4. Install both "Simple FOC" and "Simple FOC drivers" libraries

  5. 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

  1. Check pole pairs: Ensure the motor pole pair count is correct

  2. Verify sensor direction: The sensor and motor rotation should be synchronized

  3. Power supply: Ensure adequate power supply capacity

  4. 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

  1. Increase loop frequency: Ensure motor.loopFOC() runs at >1kHz

  2. Disable serial monitoring: Remove motor.monitor() calls for production code

  3. 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

  1. Always initialize components in the correct order: sensor → driver → motor

  2. Use meaningful variable names for different motors in multi-motor projects

  3. Implement proper error handling for initialization failures

Hardware Considerations

  1. Use proper decoupling capacitors on power supplies

  2. Keep sensor wiring away from high-current motor wires

  3. Ensure adequate cooling for motor drivers

  4. Use twisted pair cables for encoder signals

Performance Tuning

  1. Start with default PID parameters and adjust gradually

  2. Monitor motor current and temperature during testing

  3. 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.

Post a comment