e-foc
April 13, 2026 · View on GitHub
e-foc
An embedded motor control application implementing Field-Oriented Control (FOC) for BLDC and PMSM motors with strict real-time and memory constraints. Built for deterministic execution on resource-constrained microcontrollers.
Overview
This project provides a production-ready motor control implementation designed for embedded systems with no heap allocation, deterministic execution, and minimal memory footprint. It demonstrates FOC algorithms with complete hardware integration for ST and TI microcontrollers.
Features
Core Capabilities
- Field-Oriented Control (FOC): Complete implementation for BLDC and PMSM motors
- Space Vector Modulation (SVM): Efficient PWM generation
- PID Control: Anti-windup implementations for current and velocity loops
- Sensored Control: Encoder and Hall sensor feedback integration
- Auto-Tuning: Resistance and Inductance estimation
- Real-Time Performance: Deterministic execution with no heap allocation
Embedded Constraints
- Zero Heap Allocation: All memory statically allocated at compile-time
- Fixed Memory Footprint: Uses
infra::BoundedVector,infra::BoundedStringinstead of standard containers - Minimal Stack Usage: No recursion, predictable call depths
- Platform Abstraction:
PlatformFactoryinterface with ST and TI implementations
Simulation & Testing
- C++ Simulator: Mathematical models for motor evaluation and curve plotting
- Unit Tests: Comprehensive GoogleTest coverage for control algorithms
- Hardware-in-the-Loop Ready: Mockable interfaces for testability
Getting Started
Prerequisites
- CMake 3.24 or later
- Compatible toolchain for embedded targets (ARM GCC)
- Development board: EK-TM4C1294XL (TI) or STM32F407G-DISC1 (ST)
- Basic understanding of motor control and embedded systems
Quick Start
- Clone the repository with submodules
git clone --recursive https://github.com/embedded-pro/e-foc.git
cd e-foc
- Build for host simulation
cmake --preset host
cmake --build --preset host-Debug
- Run tests
ctest --preset host
- Build for embedded target (example: TI EK-TM4C1294XL)
cmake --preset EK-TM4C1294XL
cmake --build --preset EK-TM4C1294XL-Debug
Project Structure
e-foc/
├── core/ # FOC library code (no application entry points)
│ ├── foc/ # Field-Oriented Control
│ │ ├── interfaces/ # Abstract FOC interfaces (Foc.hpp, Driver.hpp, Units.hpp)
│ │ ├── implementations/ # Clarke/Park, SVM, torque/speed/position loops, Runner
│ │ └── instantiations/ # Concrete wiring of FOC components
│ ├── platform_abstraction/ # Platform abstraction interfaces and shared adapters
│ │ ├── PlatformFactory.hpp # Abstract factory for peripherals
│ │ ├── AdcPhaseCurrentMeasurement.hpp
│ │ ├── CanBusAdapter.hpp
│ │ ├── QuadratureEncoderDecorator.hpp
│ │ └── MotorFieldOrientedControllerAdapter.hpp
│ ├── services/ # Application-level services
│ │ ├── alignment/ # Motor alignment and offset detection
│ │ ├── cli/ # Command-line interface service
│ │ ├── electrical_system_ident/ # Resistance/inductance estimation
│ │ ├── mechanical_system_ident/ # Friction and inertia estimation
│ │ └── non_volatile_memory/ # NVM persistence service
│ └── state_machine/ # FOC motor lifecycle state machine (Idle/Calibrating/Ready/Enabled/Fault)
├── integration_tests/ # BDD integration tests (Cucumber/Gherkin)
│ ├── features/ # Gherkin .feature files
│ ├── steps/ # Step definitions
│ ├── hooks/ # Before/After scenario hooks
│ ├── main/ # Test executable entry point
│ └── support/ # Fixture, mocks, and bridge
├── targets/ # Application entry points and platform implementations
│ ├── sync_foc_sensored/ # Synchronous FOC with encoder feedback
│ ├── hardware_test/ # Hardware validation application
│ └── platform_implementations/ # Platform-specific PlatformFactory implementations
│ ├── host/ # Host simulation (GoogleTest stubs/mocks)
│ ├── st/ # STM32 platform implementation
│ └── ti/ # TI Tiva C platform implementation
├── tools/ # Host-side developer tools
│ ├── simulator/ # C++ motor simulators (torque, speed, position control)
│ └── can_commander/ # CAN bus command interface tool
├── infra/ # Infrastructure submodules
│ ├── embedded-infra-lib/ # Bounded containers, build helpers, toolchain CMake
│ ├── numerical-toolbox/ # PID, filters, fixed-point algorithms
│ ├── can-lite/ # CAN protocol library
│ └── hal/ # Hardware abstraction layer (ST, TI)
├── documentation/ # Architecture, design, theory, and requirements docs
└── build/ # Build artifacts (generated, not committed)
Key Design Principles
Memory Management
- No Heap Allocation: All memory is statically allocated at compile-time
- Bounded Containers: Uses
infra::BoundedVector,infra::BoundedStringinstead of STL containers - Fixed Memory Footprint: Predictable RAM usage for resource-constrained systems
Real-Time Performance
- Deterministic Execution: No dynamic allocation or unbounded loops in control paths
- Minimal Branching: Optimized control loops for consistent timing
- ISR-Safe Design: Interrupt service routines avoid virtual calls and complex operations
Architecture
- Dependency Injection: Constructor injection for testability and flexibility
- Platform Abstraction: Clean separation between application logic and hardware
- Interface-Driven Design: Pure virtual interfaces enable mocking and testing
How to Run the Simulator
The simulator includes a Qt-based GUI for real-time visualization. Since the development environment runs inside a Dev Container, an X server on the host machine is required to display the GUI.
Host Setup
Windows
- Install VcXsrv (free) or X410 from the Microsoft Store.
- Launch VcXsrv with the following settings:
- Multiple windows
- Start no client
- Disable access control (checked)
- Open the project in VS Code and reopen in the Dev Container.
Linux
- Allow Docker containers to access your X server:
xhost +local:docker - Open the project in VS Code and reopen in the Dev Container.
Note: The Dev Container sets
DISPLAY=host.docker.internal:0.0to forward GUI windows over TCP. On Linux, if you prefer Unix socket forwarding, you can overrideDISPLAYto:0inside the container and add a bind mount for/tmp/.X11-unix.
Build & Run
Inside the Dev Container terminal:
cmake --preset host
cmake --build --preset host-Debug
Run the speed control simulator:
./build/host/bin/Debug/e_foc.tool.simulator.speed_control
Run the torque control simulator:
./build/host/bin/Debug/e_foc.tool.simulator.torque_control
Run with custom parameters (example):
./build/host/bin/Debug/e_foc.tool.simulator.speed_control --help
Troubleshooting
| Problem | Solution |
|---|---|
cannot open display | Ensure the X server is running on the host and "Disable access control" is enabled |
| Black window or no rendering | Set LIBGL_ALWAYS_INDIRECT=1 (already configured in the Dev Container) |
| Windows firewall blocks display | Allow VcXsrv (vcxsrv.exe) through the Windows firewall for private networks |
Documentation
Architecture
| Document | Description |
|---|---|
| System Architecture | High-level system architecture and component relationships |
Design
| Document | Description |
|---|---|
| FOC Transforms | Clarke and Park transform design |
| FOC Torque Control | Torque (current) control loop design |
| FOC Speed Control | Speed control loop design |
| FOC Position Control | Position control loop design |
| Alignment Service | Motor alignment and offset detection service |
| CLI Service | Command-line interface service |
| Electrical Identification Service | Resistance and inductance estimation service |
| Mechanical Identification Service | Friction and inertia estimation service |
| NVM Service | Non-volatile memory persistence service |
| Integration Testing Design | Fixture design, calibration flow, CAN bridge |
Requirements
| Document | Description |
|---|---|
| State Machine Requirements | Lifecycle state transitions and NVM boot behaviour |
| FOC Torque Controller Requirements | Torque control loop functional requirements |
| CAN-to-State-Machine Integration Requirements | CAN command to state machine mapping requirements |
Theory
| Document | Description |
|---|---|
| FOC Theory | Field-Oriented Control theory and control block diagrams |
| Motor Alignment | Motor alignment and offset detection theory |
| Resistance & Inductance Estimation | Parameter estimation theory |
| Friction & Inertia Estimation | Mechanical parameter estimation theory |
Performance
| Document | Description |
|---|---|
| Performance Optimization Guide | High-performance embedded code, assembly analysis, cycle budgets |
Development References
| Document | Description |
|---|---|
| Copilot / Agent Instructions | Development guidelines, patterns, and constraints |
| embedded-infra-lib | Bounded containers and infrastructure library reference |
| numerical-toolbox | Reusable numerical algorithms (PID, filters, fixed-point) |
Contributing
We welcome contributions! Please follow these guidelines:
Development Workflow
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Follow the coding standards in copilot-instructions.md.
- Ensure all tests pass
- Update CHANGELOG.md according to release-please conventions
- Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Critical Guidelines
- NO heap allocation (
new,delete,malloc,free) - NO standard containers (use
infra::Bounded*alternatives) - Use fixed-size types (
uint8_t,int32_t, etc.) - Mark all non-mutating methods as
const - Write unit tests for new functionality
- Follow
.clang-formatrules for code formatting
License
This project is licensed under the MIT License - see the LICENSE file for details.