adithya-187326/vesc-can

1.0.1

Latest
uploaded 3 days ago
VESC-CAN Driver

Readme

| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |

# _VESC CAN ESP-IDF Component_

This component provides an ESP-IDF driver for controlling and monitoring VESC-based motor controllers over the CAN bus, built on the node-based TWAI driver introduced in ESP-IDF v5.5.

The driver offers a clean interface for sending motor commands and decoding VESC status broadcasts, handling the CAN frame construction, big-endian byte ordering, and fixed-point scaling defined by the VESC protocol.

## Features

- Command transmission across all VESC single-frame targets:
  - Duty cycle, RPM, position
  - Current, brake current, handbrake current
  - Relative variants of current, brake current, and handbrake current
- Off delay support for current commands (`vesc_set_target_off_delay()`)
- Status frame decoding via a drop-in TWAI receive callback (`vesc_can_on_rx_cb()`)
- Decodes all six VESC status broadcasts (`CAN_PACKET_STATUS_1` through `CAN_PACKET_STATUS_6`) into a single `vesc_data_t` struct
- Argument validation with `ESP_ERR_INVALID_ARG` on out-of-range values
- Integer-only decoded output, no floating point in the receive path
- Configurable via Kconfig
- Built on the node-based TWAI driver (`esp_twai.h` / `esp_twai_onchip.h`)

## Component Structure

```bash
vesc-can/
├── include/
│   └── vesc-can.h            # Public API
├── src/
│   └── vesc-can.c            # Implementation
├── Kconfig.projbuild         # Configuration options
├── CMakeLists.txt            # Component build definition
├── idf_component.yml         # Component manifest for ESP Registry
└── examples/
    ├── set-commands/         # Sending motor commands
    └── feedback-receive/     # Receiving and decoding status frames
```

## Configuration (Kconfig)

This component uses the following Kconfig options:
| Setting | Description | Default |
| ------------------------------- | ---------------------------- | ------- |
| `CONFIG_VESC_CAN_BUS_FREQUENCY` | CAN bus frequency (kHz) | `1000` |
| `CONFIG_VESC_ID` | VESC ID over the CAN bus | `0x60` |

Modify these using `idf.py menuconfig → VESC CAN Configuration`.

`CONFIG_VESC_ID` must match the value set in VESC Tool under App Settings → General → VESC ID.

## API

### Sending Commands

```c
esp_err_t vesc_set_target(twai_node_handle_t *handle, uint8_t vesc_id,
                          vesc_target_t target, float value);

esp_err_t vesc_set_target_off_delay(twai_node_handle_t *handle, uint8_t vesc_id,
                                    vesc_target_t target, float value,
                                    float off_delay);
```

Valid targets and their value ranges:

| Target                       | Unit    | Range               |
| ---------------------------- | ------- | ------------------- |
| `VESC_DUTY`                  | ratio   | -1.0 to 1.0         |
| `VESC_CURRENT`               | A       | Motor limit         |
| `VESC_CURRENT_BRAKE`         | A       | Motor limit         |
| `VESC_RPM`                   | RPM     | Motor limit         |
| `VESC_POSITION`              | degrees | 0 to 360            |
| `VESC_CURRENT_REL`           | ratio   | -1.0 to 1.0         |
| `VESC_CURRENT_BRAKE_REL`     | ratio   | -1.0 to 1.0         |
| `VESC_CURRENT_HANDBRAKE`     | A       | Motor limit         |
| `VESC_CURRENT_HANDBRAKE_REL` | ratio   | -1.0 to 1.0         |

Values bounded by the motor limit are not range-checked by the driver; the VESC firmware truncates them to its configured maximum.

`vesc_set_target_off_delay()` accepts only `VESC_CURRENT` and `VESC_CURRENT_REL`. The off delay is specified in seconds and keeps the current controller running after the commanded current falls below the minimum.

### Receiving Status Frames

```c
bool vesc_can_on_rx_cb(twai_node_handle_t handle,
                       const twai_rx_done_event_data_t *edata, void *user_ctx);
```

Assign directly to `twai_event_callbacks_t.on_rx_done`, passing a pointer to a `vesc_data_t` as the user context:

```c
twai_event_callbacks_t can_callbacks = {
    .on_rx_done = vesc_can_on_rx_cb,
};
vesc_data_t motor;
ESP_ERROR_CHECK(twai_node_register_event_callbacks(node_handle, &can_callbacks, &motor));
```

The callback returns `true` when a recognized status frame was decoded, `false` otherwise.

### Decoded Data

`vesc_data_t` fields, populated as the corresponding status frames arrive:

| Field                          | Unit    | Source            |
| ------------------------------ | ------- | ----------------- |
| `erpm`                         | RPM     | `STATUS_1`        |
| `current`                      | mA      | `STATUS_1`        |
| `duty_cycle`                   | %       | `STATUS_1`        |
| `amp_hours_used`               | mAh     | `STATUS_2`        |
| `amp_hours_regen`              | mAh     | `STATUS_2`        |
| `watt_hours_used`              | mWh     | `STATUS_3`        |
| `watt_hours_regen`             | mWh     | `STATUS_3`        |
| `mosfet_temp`                  | °C      | `STATUS_4`        |
| `motor_temp`                   | °C      | `STATUS_4`        |
| `input_current`                | mA      | `STATUS_4`        |
| `pid_pos`                      | degrees | `STATUS_4`        |
| `tacho`                        | erev    | `STATUS_5`        |
| `input_voltage`                | mV      | `STATUS_5`        |
| `adc1_voltage` to `adc3_voltage` | mV    | `STATUS_6`        |
| `ppm`                          | %       | `STATUS_6`        |
| `vesc_id`                      | —       | All status frames |

Status messages must be enabled in VESC Tool under App Settings → General → CAN Status Messages Rate.

## Usage

Refer to the `/examples` directory for:

- set-commands: Sending current and RPM commands to a VESC
- feedback-receive: Receiving and decoding status broadcasts

## Notes

- Requires ESP-IDF ≥ 5.5 for the node-based TWAI driver. The legacy `driver/twai.h` driver is not compatible and must not be used alongside it.
- A CAN transceiver is required between the ESP and the VESC. The ESP cannot drive the differential bus directly.
- The VESC stops the motor if no CAN frame is received within its configured timeout (0.5 s by default). Re-send commands at a fixed rate to prevent this.
- `vesc_can_on_rx_cb()` runs in ISR context. Keep any additional processing short.
- The CAN bitrate configured here must match the VESC's CAN baud rate setting.
- Tested on ESP32-S3 with two Flipsky FSESC 6.7 Mini Pro controllers on the bus at 1 Mbit/s, in both transmit and receive.

## References

- [VESC CAN-Bus Communication documentation](https://github.com/vedderb/bldc/blob/master/documentation/comm_can.md)
- [VESC6 CAN Commands and Telemetry](https://vesc-project.com/sites/default/files/imce/u15301/VESC6_CAN_CommandsTelemetry.pdf)

## License

Licensed under the **MIT License**. \
See the [LICENSE](LICENSE) file for full text.

## Maintainer

**Author:** Adithya Venkata Narayanan ([Adithya-187326](https://github.com/adithya-187326))
**Version:** 1.0.0
**Registry:** ESP Component Registry

Links

Maintainer

  • Adithya Venkata Narayanan <adithyavnarayanan@gmail.com>
To add this component to your project, run:

idf.py add-dependency "adithya-187326/vesc-can^1.0.1"

download archive

Stats

  • Archive size
    Archive size ~ 14.54 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

adithya-187326/vesc-can version: 1.0.1
|