Skip to content
embedded-proPublic

About

Comprehensive embedded motor control toolkit demonstrating Field-Oriented Control (FOC) and PID implementations for DC, BLDC, and PMSM motors

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Latest commit

 

History

379 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

e-foc

Quality Gate Status Coverage Duplicated Lines (%) Vulnerabilities

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::BoundedString instead of standard containers
  • Minimal Stack Usage: No recursion, predictable call depths
  • Platform Abstraction: PlatformFactory interface 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
  • Ninja, ccache, and Qt 6 (Core, Network, Widgets) for the host preset — the host build always configures tools/
  • 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

  1. Clone the repository with submodules
git clone --recursive https://github.com/embedded-pro/e-foc.git
cd e-foc
  1. Build for host simulation
cmake --preset host
cmake --build --preset host-Debug
  1. Run tests
ctest --preset host
  1. 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/              # FOC vocabulary and contracts (Foc.hpp, Signals.hpp, MotorModel.hpp, LoopTunings.hpp, Execution.hpp, Units.hpp)
│   │   ├── math/                    # Generic numerics (FastTrigonometry.hpp, AngleWrap.hpp)
│   │   ├── transforms/              # Clarke/Park transforms and Space Vector Modulation
│   │   ├── selection/               # Heap-free runtime controller selection
│   │   ├── current_loop/            # PID/decoupled-PID/deadbeat/sliding-mode current regulators
│   │   ├── speed_loop/              # PID/LQI/ADRC/two-DOF speed regulators
│   │   ├── cascade/                 # Torque/speed/position cascade orchestration and gain design
│   │   └── instantiations/          # Execution wiring (Runner, FocController)
│   ├── platform_abstraction/        # Platform abstraction interfaces and shared adapters
│   │   ├── interfaces/              # Hardware ports in namespace drivers (ThreePhaseInverter, Encoder, HallSensor)
│   │   ├── PlatformFactory.hpp      # Abstract factory for peripherals
│   │   ├── AdcPhaseCurrentMeasurement.hpp
│   │   ├── CanBusAdapter.hpp
│   │   └── QuadratureEncoderDecorator.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
│   ├── can/                         # FOC motor CAN category (server, client, bridge, wire contract)
│   ├── supervision/                 # Runtime plausibility monitors
│   └── 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)
│       ├── qemu/                    # Emulated Cortex-M4 platform for software-in-the-loop tests
│       ├── 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
│   └── hardware_bridge/             # Terminal/CAN/serial bridge client (Qt) for HIL tests
├── 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::BoundedString instead 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

  1. Install VcXsrv (free) or X410 from the Microsoft Store.
  2. Launch VcXsrv with the following settings:
    • Multiple windows
    • Start no client
    • Disable access control (checked)
  3. Open the project in VS Code and reopen in the Dev Container.

Linux

  1. Allow Docker containers to access your X server:
    xhost +local:docker
  2. Open the project in VS Code and reopen in the Dev Container.

Note: The Dev Container sets DISPLAY=host.docker.internal:0.0 to forward GUI windows over TCP. On Linux, if you prefer Unix socket forwarding, you can override DISPLAY to :0 inside 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 simulator:

./build/host/bin/Debug/e_foc.tool.simulator

On launch, a dialog asks which controller to simulate (Torque, Speed, or Position). The chosen controller assembles the corresponding loops; the main window provides tabbed Parameters/Configuration and Phase Signals/RLS Estimates panels around an always-visible SVPWM hexagon.

The shared UI library

The three desktop tools render through ui-cpp, fetched at configure time and pinned in CMakeLists.txt to an exact commit. Consuming a newer ui-cpp is a deliberate edit to that pin, reviewed like any other change, rather than something a fresh configure does on its own; changing it re-fetches on the next configure.

To build against a local ui-cpp working tree instead of the pinned commit, which is what makes bisecting across the two repositories possible:

cmake --preset host -DFETCHCONTENT_SOURCE_DIR_UI=/path/to/ui-cpp

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

Releases

Each release carries:

Asset Content
e_foc-firmware-<board>-<tag>.tar.gz .elf and .hex of every application built for the board
e_foc-firmware-EK-TM4C1294XL-<application>-<tag>.hex ready-to-flash images for the EK-TM4C1294XL (sync_foc_sensored, hardware_test)
e_foc-source-<tag>.tar.gz the complete source with every submodule (GitHub's own source archives omit them)
e_foc-can_commander-*, e_foc-simulator-* desktop tools for Linux and Windows (see below)
eFocDesign.pdf the complete design booklet
e_foc-documentation-<tag>.zip the individual design, theory and requirements documents as PDFs

Configuring a build from the source archive still downloads the dependencies CMake declares with FetchContent (such as ui-cpp and GoogleTest).

Verifying a download

Every release asset carries a build-provenance attestation, signed through Sigstore by the release workflow, which proves the file was built from this repository by GitHub Actions. Check one with the GitHub CLI:

gh attestation verify e_foc-can_commander-<tag>-windows-x86_64-setup.exe --repo embedded-pro/e-foc

Once code signing is enabled for the project (see .github/signpath/README.md), the Windows CAN Commander executable and installer are also Authenticode-signed, so Windows shows the publisher instead of Unknown publisher.

CAN Commander

e-foc CAN Commander commands and monitors the e-foc motor controllers on one CAN bus — up to eight, each addressed by its node ID. Every controller whose heartbeat is seen gets its own tab (you can also add one by node ID) with start/stop, control mode, setpoints, loop bandwidths, telemetry and identified parameters; an overview row keeps every motor's state and faults in view, and one always-visible EMERGENCY STOP ALL (Esc) reaches every motor.

Each controller needs its own node ID. On the EK-TM4C1294XL, fit the board-ID jumpers on PK0–PK2 (to ground; PK0 is bit 0): with the default configuration a board answers as node 1 + its board ID, so boards jumpered 0–7 become nodes 1–8. Jumpers are read at reset only.

Supported CAN adapters

Adapter Linux Windows Interface name
SocketCAN devices Yes — can0
CANable and other slcan adapters Yes Yes slcan:/dev/ttyACM0, slcan:COM3
candleLight (gs_usb firmware) Through SocketCAN Yes, no driver to install candleLight:1
PEAK PCAN-USB Through SocketCAN Yes, with the PEAK driver package PCAN:1
Kvaser Through SocketCAN Yes, with the Kvaser CANlib driver Kvaser:0

On Linux, slcan needs the user in the dialout group (sudo usermod -aG dialout $USER, then log in again).

Install

Download the installer for your platform from the latest release:

Platform Asset Install
Windows x86-64 e_foc-can_commander-<tag>-windows-x86_64-setup.exe Run it; start from Start → e-foc CAN Commander
Debian/Ubuntu x86-64 e_foc-can_commander-<tag>-linux-x86_64.deb sudo apt install ./e_foc-can_commander-<tag>-linux-x86_64.deb

The .deb is built on Ubuntu 24.04 and needs a distribution of that generation or newer. Portable archives (.zip, .tar.gz) remain available. On Linux, bring a SocketCAN interface up first, e.g. sudo ip link set can0 up type can bitrate 1000000. e-foc-can-commander --version prints the installed version without opening a window (on Windows, run it from a console).

Issue log, bug reports and updates

  • Every session writes an issue log (UTC timestamps, rotated at 1 MiB, three files) to ~/.local/share/e-foc/CAN Commander/logs on Linux or %LOCALAPPDATA%\e-foc\CAN Commander\logs on Windows. Help → Open Log Folder opens it.
  • Help → Report Issue opens a pre-filled GitHub issue with the version, OS and recent log lines for you to review and submit.
  • At startup and every 24 hours the tool checks the latest GitHub release and shows a banner when a newer version exists. Install Update… downloads the installer, checks it against the SHA-256 published with the release, then installs it and restarts — after Windows asks for permission, or after your password on Linux. Installing waits until the CAN bus is disconnected. Portable archives get a download link instead. Turn the checks off with Help → Check for Updates Automatically or --no-update-check.

Build the installers locally

cmake --preset host && cmake --build build/host --config Release --target e_foc.tool.can_commander
cpack --config build/host/tools/can_commander/installer/CPackConfig.cmake -C Release -G DEB   # Linux
cpack --config build/tools/can_commander/installer/CPackConfig.cmake -C Release -G NSIS        # Windows, NSIS on PATH

Design: documentation/design/tool-can-commander.md.

Documentation

Architecture Documents

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
Current Offsets Service Current sensor offset calibration service
Dead-Time Compensation Service Duty correction for the bridge's dead time
Cogging Compensation Service Cogging torque map and current feed-forward
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
CAN Commander Desktop commander, issue log, installers

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)

License

This project is licensed under the e-foc Non-Commercial License. Commercial use is not permitted without prior written permission from the project owner. See the LICENSE file for details.

Third-party components and submodules keep their own license terms as documented in their respective directories.

About

Comprehensive embedded motor control toolkit demonstrating Field-Oriented Control (FOC) and PID implementations for DC, BLDC, and PMSM motors

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages