Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vedderb/bldc/llms.txt

Use this file to discover all available pages before exploring further.

Field Oriented Control (FOC) is the default and most capable motor control algorithm in VESC firmware. It controls the d-axis and q-axis currents independently in a rotating reference frame, enabling smooth torque, high efficiency, and precise speed and position control.

Sensor modes

FOC sensor mode is configured via mc_foc_sensor_mode in datatypes.h. The default is FOC_SENSOR_MODE_SENSORLESS.
typedef enum {
    FOC_SENSOR_MODE_SENSORLESS = 0,
    FOC_SENSOR_MODE_ENCODER,
    FOC_SENSOR_MODE_HALL,
    FOC_SENSOR_MODE_HFI,
    FOC_SENSOR_MODE_HFI_START,
    FOC_SENSOR_MODE_HFI_V2,
    FOC_SENSOR_MODE_HFI_V3,
    FOC_SENSOR_MODE_HFI_V4,
    FOC_SENSOR_MODE_HFI_V5,
    FOC_SENSOR_MODE_ENCODER_AB
} mc_foc_sensor_mode;
The flux observer estimates rotor position from stator voltages and currents. No position sensor is required. The motor coasts through open-loop at low speeds until the observer locks in, controlled by MCCONF_FOC_OPENLOOP_RPM (default: 1500 ERPM) and the open-loop hysteresis/timing parameters.
Uses an incremental (ABI) encoder for rotor position. Requires encoder offset calibration. Ratio and inversion are set by MCCONF_FOC_ENCODER_RATIO (default: 7.0) and MCCONF_FOC_ENCODER_INVERTED (default: false).
Encoder AB mode — uses only the A and B signals (no index pulse). Useful when the index channel is unavailable.
Hall effect sensors provide 60-degree resolution commutation. Sensor angles are stored in the FOC hall table (MCCONF_FOC_HALL_TAB_0 through MCCONF_FOC_HALL_TAB_7). Hall interpolation is disabled below MCCONF_FOC_HALL_INTERP_ERPM (default: 500 ERPM) to avoid noise at low speeds.
High-Frequency Injection. A high-frequency voltage is superimposed on the motor to detect rotor position from inductance anisotropy. Intended for salient-pole motors (e.g., IPM motors). See the HFI section below.
Sensorless mode that uses HFI only during startup and low-speed operation to resolve initial rotor position, then hands off to the sensorless observer. Avoids open-loop coasting on startup.
Revised HFI algorithm (V2) with a correction gain (MCCONF_FOC_HFI_GAIN, default: 0.3) and max error truncation (MCCONF_FOC_HFI_MAX_ERR, default: 0.30).
HFI V3 — an incremental variation of the V2 algorithm.
HFI V4 — further refined HFI variant.
HFI V5 — latest HFI variant with additional hysteresis control via MCCONF_FOC_HFI_HYST (default: 0.0).

HFI (High-Frequency Injection)

HFI detects rotor position at standstill and low speeds by injecting a high-frequency test voltage and measuring the resulting current response. It requires a motor with significant inductance anisotropy (Ld ≠ Lq).

HFI key parameters

ParameterDefaultDescription
MCCONF_FOC_HFI_VOLTAGE_START20 VInjection voltage during ambiguity resolution at startup
MCCONF_FOC_HFI_VOLTAGE_RUN4 VInjection voltage during normal HFI tracking
MCCONF_FOC_HFI_VOLTAGE_MAX6 VInjection voltage at maximum motor current
MCCONF_FOC_HFI_SAMPLESHFI_SAMPLES_16Samples per electrical revolution (8, 16, or 32)
MCCONF_FOC_HFI_START_SAMPLES5Samples used at startup to resolve pole ambiguity
MCCONF_FOC_SL_ERPM_HFI3000 ERPMERPM above which the observer takes over from HFI
MCCONF_FOC_HFI_RESET_ERPM500 ERPMReset HFI state when falling below this ERPM
MCCONF_FOC_HFI_OBS_OVR_SEC0.001 sContinue using observer for this long after entering HFI speed range
MCCONF_FOC_HFI_GAIN0.3Correction gain for HFI V2
MCCONF_FOC_HFI_MAX_ERR0.30Truncate HFI error above this magnitude
MCCONF_FOC_HFI_HYST0.0Sense vector offset hysteresis for HFI V5

HFI ambiguity resolution mode

Because inductance anisotropy is 180° ambiguous, HFI requires a separate step to resolve the correct pole. The ambiguity mode is set by mc_foc_hfi_amb_mode:
typedef enum {
    FOC_AMB_MODE_SIX_VECTOR = 0,
    FOC_AMB_MODE_D_SINGLE_PULSE,
    FOC_AMB_MODE_D_DOUBLE_PULSE
} mc_foc_hfi_amb_mode;
ModeDescription
FOC_AMB_MODE_SIX_VECTORApplies voltage vectors in six directions and selects the strongest response. Default.
FOC_AMB_MODE_D_SINGLE_PULSEApplies a single d-axis pulse.
FOC_AMB_MODE_D_DOUBLE_PULSEApplies two d-axis pulses with opposite polarity for more reliable detection.
Ambiguity current and threshold are set by MCCONF_FOC_HFI_AMB_CURRENT (default: 60.0 A) and MCCONF_FOC_HFI_AMB_TRES (default: 15).

Position observer

For sensorless operation, the flux observer estimates rotor position. The observer type is selected by mc_foc_observer_type:
typedef enum {
    FOC_OBSERVER_ORTEGA_ORIGINAL = 0,
    FOC_OBSERVER_MXLEMMING,
    FOC_OBSERVER_ORTEGA_LAMBDA_COMP,
    FOC_OBSERVER_MXLEMMING_LAMBDA_COMP,
    FOC_OBSERVER_MXV,
    FOC_OBSERVER_MXV_LAMBDA_COMP,
    FOC_OBSERVER_MXV_LAMBDA_COMP_LIN,
} mc_foc_observer_type;
The default observer is FOC_OBSERVER_MXLEMMING_LAMBDA_COMP. Observer gain is set by MCCONF_FOC_OBSERVER_GAIN (default: 9×10⁷; suggested starting value: 600 / L). At low duty cycles the gain is scaled down by MCCONF_FOC_OBSERVER_GAIN_SLOW (default: 0.05).

Hybrid sensor / sensorless

When using Hall or encoder feedback, you can configure the firmware to blend in the observer at higher speeds:
ParameterDefaultDescription
MCCONF_FOC_SL_ERPM_START2500 ERPMBelow this, only the sensor is used
MCCONF_FOC_SL_ERPM3500 ERPMAbove this, only the observer is used
Between MCCONF_FOC_SL_ERPM_START and MCCONF_FOC_SL_ERPM the two sources are blended linearly.

Open-loop startup (sensorless)

In sensorless mode the motor runs open-loop at low speeds before the observer has locked in. Key parameters:
ParameterDefaultDescription
MCCONF_FOC_OPENLOOP_RPM1500 ERPMOpen-loop speed target
MCCONF_FOC_OPENLOOP_RPM_LOW0.0Fraction of OPENLOOP_RPM at minimum motor current
MCCONF_FOC_SL_OPENLOOP_HYST0.1 sTime below minimum RPM before entering open-loop
MCCONF_FOC_SL_OPENLOOP_TIME0.05 sTime to remain in open-loop after ramping up
MCCONF_FOC_SL_OPENLOOP_T_LOCK0.0 sTime to lock rotor in place at start of open-loop sequence
MCCONF_FOC_SL_OPENLOOP_T_RAMP0.1 sRamp duration from 0 to open-loop RPM
MCCONF_FOC_SL_OPENLOOP_BOOST_Q0.0 AQ-axis current boost during open-loop
MCCONF_FOC_SL_OPENLOOP_MAX_Q-1.0 AQ-axis current maximum during open-loop (-1 = disabled)

Current controller

The FOC current controller (inner PI loop) operates on the d and q axes:
ParameterDefaultDescription
MCCONF_FOC_CURRENT_KP0.03Proportional gain
MCCONF_FOC_CURRENT_KI50.0Integral gain
MCCONF_FOC_F_ZV25000 HzZero-vector switching frequency
MCCONF_FOC_DT_US0.12 µsDead-time compensation

Current controller decoupling

typedef enum {
    FOC_CC_DECOUPLING_DISABLED = 0,
    FOC_CC_DECOUPLING_CROSS,
    FOC_CC_DECOUPLING_BEMF,
    FOC_CC_DECOUPLING_CROSS_BEMF
} mc_foc_cc_decoupling_mode;
The default is FOC_CC_DECOUPLING_DISABLED. Cross-coupling and BEMF feedforward can improve dynamic response at high speeds.

Motor parameters

The observer and current controller use these motor-specific parameters:
ParameterDefaultDescription
MCCONF_FOC_MOTOR_L7 µHPhase inductance
MCCONF_FOC_MOTOR_R0.015 ΩPhase resistance
MCCONF_FOC_MOTOR_FLUX_LINKAGE0.00245 WbFlux linkage
MCCONF_FOC_MOTOR_LD_LQ_DIFF0.0 HDifference between d and q inductance (for MTPA)
Use VESC Tool’s motor measurement wizard to automatically detect resistance, inductance, and flux linkage for your specific motor.

PLL speed estimator

A phase-locked loop (PLL) tracks the rotor angle from the observer output:
ParameterDefaultDescription
MCCONF_FOC_PLL_KP2000.0PLL proportional gain
MCCONF_FOC_PLL_KI30000.0PLL integral gain

Field weakening

Field weakening extends operating speed above the rated RPM by injecting negative d-axis current:
ParameterDefaultDescription
MCCONF_FOC_FW_CURRENT_MAX0.0 AMaximum field weakening current (0 = disabled)
MCCONF_FOC_FW_DUTY_START0.8Duty cycle fraction at which field weakening begins
MCCONF_FOC_FW_RAMP_TIME0.0 sRamp time for field weakening current
MCCONF_FOC_FW_Q_CURRENT_FACTOR0.05Fraction of FW current fed to the q-axis to decelerate when setpoint is 0
Field weakening increases motor and controller temperatures. Ensure adequate thermal headroom before enabling it.

MTPA (Maximum Torque Per Amp)

MTPA exploits d/q inductance asymmetry to maximize torque output at a given current. It is configured by MCCONF_FOC_MTPA_MODE and requires MCCONF_FOC_MOTOR_LD_LQ_DIFF to be non-zero.

FOC functions (mcpwm_foc)

The mcpwm_foc module implements the FOC algorithm. You typically call it through mc_interface, but the direct API is available:
// Initialization
void mcpwm_foc_init(mc_configuration *conf_m1, mc_configuration *conf_m2);
void mcpwm_foc_deinit(void);
bool mcpwm_foc_init_done(void);
void mcpwm_foc_set_configuration(mc_configuration *configuration);

// Control
void mcpwm_foc_set_duty(float dutyCycle);
void mcpwm_foc_set_duty_noramp(float dutyCycle);
void mcpwm_foc_set_pid_speed(float rpm);
void mcpwm_foc_set_pid_pos(float pos);
void mcpwm_foc_set_current(float current);
void mcpwm_foc_set_brake_current(float current);
void mcpwm_foc_set_handbrake(float current);
void mcpwm_foc_set_openloop_current(float current, float rpm);
void mcpwm_foc_set_openloop_phase(float current, float phase);
void mcpwm_foc_set_openloop_duty(float dutyCycle, float rpm);
void mcpwm_foc_set_openloop_duty_phase(float dutyCycle, float phase);
void mcpwm_foc_set_fw_override(float current);  // override field weakening current
void mcpwm_foc_release_motor(void);
void mcpwm_foc_stop_pwm(bool is_second_motor);

// State
mc_state mcpwm_foc_get_state(void);
mc_control_mode mcpwm_foc_control_mode(void);
bool mcpwm_foc_is_dccal_done(void);

// Speed and position
float mcpwm_foc_get_rpm(void);
float mcpwm_foc_get_rpm_fast(void);
float mcpwm_foc_get_rpm_faster(void);
float mcpwm_foc_get_phase(void);             // estimated rotor phase (degrees)
float mcpwm_foc_get_phase_observer(void);    // observer phase estimate
float mcpwm_foc_get_phase_bemf(void);        // BEMF-derived phase
float mcpwm_foc_get_phase_encoder(void);     // encoder phase
float mcpwm_foc_get_phase_hall(void);        // hall-derived phase

// dq-frame values
float mcpwm_foc_get_id(void);               // d-axis current
float mcpwm_foc_get_iq(void);               // q-axis current
float mcpwm_foc_get_id_set(void);
float mcpwm_foc_get_iq_set(void);
float mcpwm_foc_get_vd(void);               // d-axis voltage
float mcpwm_foc_get_vq(void);               // q-axis voltage

// Observer state
float mcpwm_foc_get_est_lambda(void);       // estimated flux linkage
float mcpwm_foc_get_est_res(void);          // estimated stator resistance
float mcpwm_foc_get_est_ind(void);          // estimated inductance

// Motor measurement utilities
int mcpwm_foc_measure_resistance(float current, int samples, bool stop_after, float *resistance);
int mcpwm_foc_measure_inductance(float duty, int samples, float *curr, float *ld_lq_diff, float *inductance);
int mcpwm_foc_measure_inductance_current(float curr_goal, int samples, float *curr, float *ld_lq_diff, float *inductance);
int mcpwm_foc_encoder_detect(float current, bool print, float *offset, float *ratio, bool *inverted);

Sample modes

FOC sampling behavior is configurable:
// When to sample voltages for the control update
typedef enum {
    FOC_CONTROL_SAMPLE_MODE_V0 = 0,
    FOC_CONTROL_SAMPLE_MODE_V0_V7,
    FOC_CONTROL_SAMPLE_MODE_V0_V7_INTERPOL
} mc_foc_control_sample_mode;

// Which current sensor readings to use
typedef enum {
    FOC_CURRENT_SAMPLE_MODE_LONGEST_ZERO = 0,
    FOC_CURRENT_SAMPLE_MODE_ALL_SENSORS,
    FOC_CURRENT_SAMPLE_MODE_HIGH_CURRENT,
    FOC_CURRENT_SAMPLE_MODE_BEST_SENSOR  // experimental
} mc_foc_current_sample_mode;
Defaults are FOC_CONTROL_SAMPLE_MODE_V0 and FOC_CURRENT_SAMPLE_MODE_LONGEST_ZERO.