Skip to main content
VESC firmware includes a BMS module (bms.c / bms.h) that receives battery state data from a BMS over CAN bus and uses it to dynamically limit motor current. The module is designed around the VESC BMS but is intentionally extensible to other BMS types.

Hardware type

Boards that run VESC firmware as a BMS (rather than as a motor controller) declare HW_TYPE_VESC_BMS in datatypes.h:
A motor controller board that communicates with a separate BMS over CAN uses HW_TYPE_VESC and enables BMS support through the bms_config structure in its application configuration.

BMS types

The supported BMS types are listed in the BMS_TYPE enum:
To add support for a different BMS, add a new value to BMS_TYPE and update bms_process_can_frame() in bms.c to decode its CAN messages.

Configuration

BMS behavior is controlled by the bms_config structure, which is part of the application configuration (app_configuration.bms in datatypes.h):

CAN forwarding mode

fwd_can_mode controls whether the VESC forwards raw BMS CAN frames to a connected host:

BMS values

The BMS module maintains a bms_values structure populated from incoming CAN frames. Retrieve it with bms_get_values():
Constants BMS_MAX_CELLS and BMS_MAX_TEMPS cap the array sizes at 50 entries each.

CAN packet types

The VESC BMS communicates over extended-frame CAN. bms_process_can_frame() handles the following packet IDs: Each frame is identified by its upper bits; the lower 8 bits carry the BMS CAN node ID. If more than one VESC BMS is on the bus, the module tracks whichever BMS last updated values within the MAX_CAN_AGE_SEC window (2 seconds):

Per-BMS statistics

For multi-BMS setups the module also tracks per-node statistics using bms_soc_soh_temp_stat:
The module keeps separate statistics for: highest temperature BMS, lowest SOC BMS, highest SOC BMS, lowest cell voltage BMS, and highest cell voltage BMS.

Current limiting

bms_update_limits() adjusts the motor controller’s input current limits based on live BMS data. Call it from the current-limiting code path, passing the configured min/max current values:
The function scales current linearly between the *_start and *_end thresholds defined in bms_config. Any of the following conditions can trigger derating:
  • Cell temperature above t_limit_start
  • SOC below soc_limit_start
  • Minimum cell voltage below vmin_limit_start
  • Maximum cell voltage above vmax_limit_start (charge current only)

Initialization

Call bms_init() once at startup, passing a pointer to the BMS configuration from the application config:
This zeros all internal state and sets can_id to -1, indicating no BMS has been seen yet.

CAN status broadcast

Call bms_send_status_can() periodically to broadcast the current BMS values to other nodes on the CAN bus. This is used when the VESC itself acts as a CAN-to-USB bridge for the BMS.