Compare commits
2 Commits
170c64eec1
...
aa90ea2fa7
| Author | SHA1 | Date | |
|---|---|---|---|
| aa90ea2fa7 | |||
| a54b1c5613 |
@ -157,12 +157,6 @@
|
|||||||
// Jetson: USART6 (PC6=TX, PC7=RX)
|
// Jetson: USART6 (PC6=TX, PC7=RX)
|
||||||
// Debug: UART5 (PC12=TX, PD2=RX)
|
// Debug: UART5 (PC12=TX, PD2=RX)
|
||||||
|
|
||||||
// --- ESC Backend Selection (Issue #388) ---
|
|
||||||
// Pluggable ESC abstraction layer — supports multiple backends:
|
|
||||||
// HOVERBOARD: EFeru FOC (USART2 @ 115200) — current default
|
|
||||||
// VESC: FSESC 4.20 Plus (USART6 @ 921600, balance mode) — future
|
|
||||||
#define ESC_BACKEND HOVERBOARD /* HOVERBOARD or VESC */
|
|
||||||
|
|
||||||
// --- CRSF / ExpressLRS ---
|
// --- CRSF / ExpressLRS ---
|
||||||
// CH1[0]=steer CH2[1]=throttle CH5[4]=arm CH6[5]=mode
|
// CH1[0]=steer CH2[1]=throttle CH5[4]=arm CH6[5]=mode
|
||||||
#define CRSF_ARM_THRESHOLD 1750 /* CH5 raw value; > threshold = armed */
|
#define CRSF_ARM_THRESHOLD 1750 /* CH5 raw value; > threshold = armed */
|
||||||
|
|||||||
@ -1,79 +0,0 @@
|
|||||||
#ifndef ESC_BACKEND_H
|
|
||||||
#define ESC_BACKEND_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ESC Backend Abstraction Layer
|
|
||||||
*
|
|
||||||
* Provides a pluggable interface for different ESC implementations:
|
|
||||||
* - Hoverboard (EFeru FOC firmware, UART @ 115200)
|
|
||||||
* - VESC (via UART @ 921600, with balance mode) — future
|
|
||||||
*
|
|
||||||
* Allows motor_driver.c to remain ESC-agnostic. Backend selection
|
|
||||||
* via ESC_BACKEND compile-time define in config.h.
|
|
||||||
*
|
|
||||||
* Issue #388: ESC abstraction layer
|
|
||||||
* Blocks Issue #383: VESC integration
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Telemetry snapshot from ESC (polled on-demand) */
|
|
||||||
typedef struct {
|
|
||||||
int16_t speed; /* Motor speed (PWM duty or RPM, backend-dependent) */
|
|
||||||
int16_t steer; /* Steering position (0 = centered) */
|
|
||||||
uint16_t voltage_mv; /* Battery voltage in millivolts */
|
|
||||||
int16_t current_ma; /* Motor current in milliamps (signed: discharge/charge) */
|
|
||||||
int16_t temperature_c; /* ESC temperature in °C */
|
|
||||||
uint16_t fault; /* Fault code (backend-specific) */
|
|
||||||
} esc_telemetry_t;
|
|
||||||
|
|
||||||
/* Virtual function table for ESC backends */
|
|
||||||
typedef struct {
|
|
||||||
/* Initialize ESC hardware and UART (called once at startup) */
|
|
||||||
void (*init)(void);
|
|
||||||
|
|
||||||
/* Send motor command to ESC (called at ~50Hz from motor_driver_update)
|
|
||||||
* speed: -1000..+1000 (forward/reverse)
|
|
||||||
* steer: -1000..+1000 (left/right)
|
|
||||||
*/
|
|
||||||
void (*send)(int16_t speed, int16_t steer);
|
|
||||||
|
|
||||||
/* Emergency stop: send zero and disable output
|
|
||||||
* (called from safety or mode manager)
|
|
||||||
*/
|
|
||||||
void (*estop)(void);
|
|
||||||
|
|
||||||
/* Query current ESC state
|
|
||||||
* Returns latest telemetry snapshot (may be cached/stale on some backends).
|
|
||||||
* Safe to call from any context (non-blocking).
|
|
||||||
*/
|
|
||||||
void (*get_telemetry)(esc_telemetry_t *out);
|
|
||||||
|
|
||||||
/* Optional: resume from estop (not all backends use this) */
|
|
||||||
void (*resume)(void);
|
|
||||||
} esc_backend_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Register a backend implementation at runtime.
|
|
||||||
* Typically called during init sequence before motor_driver_init().
|
|
||||||
*/
|
|
||||||
void esc_backend_register(const esc_backend_t *backend);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the currently active backend.
|
|
||||||
* Returns pointer to vtable; nullptr if no backend registered.
|
|
||||||
*/
|
|
||||||
const esc_backend_t *esc_backend_get(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* High-level convenience wrappers (match motor_driver.c interface).
|
|
||||||
* These call through the active backend if registered.
|
|
||||||
*/
|
|
||||||
void esc_init(void);
|
|
||||||
void esc_send(int16_t speed, int16_t steer);
|
|
||||||
void esc_estop(void);
|
|
||||||
void esc_resume(void);
|
|
||||||
void esc_get_telemetry(esc_telemetry_t *out);
|
|
||||||
|
|
||||||
#endif /* ESC_BACKEND_H */
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
#include "esc_backend.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/* Global active backend (selected at runtime or compile-time) */
|
|
||||||
static const esc_backend_t *g_active_backend = NULL;
|
|
||||||
|
|
||||||
void esc_backend_register(const esc_backend_t *backend) {
|
|
||||||
g_active_backend = backend;
|
|
||||||
if (backend && backend->init) {
|
|
||||||
backend->init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const esc_backend_t *esc_backend_get(void) {
|
|
||||||
return g_active_backend;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* High-level convenience wrappers — call through vtable */
|
|
||||||
|
|
||||||
void esc_init(void) {
|
|
||||||
if (g_active_backend && g_active_backend->init) {
|
|
||||||
g_active_backend->init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void esc_send(int16_t speed, int16_t steer) {
|
|
||||||
if (g_active_backend && g_active_backend->send) {
|
|
||||||
g_active_backend->send(speed, steer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void esc_estop(void) {
|
|
||||||
if (g_active_backend && g_active_backend->estop) {
|
|
||||||
g_active_backend->estop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void esc_resume(void) {
|
|
||||||
if (g_active_backend && g_active_backend->resume) {
|
|
||||||
g_active_backend->resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void esc_get_telemetry(esc_telemetry_t *out) {
|
|
||||||
if (out) {
|
|
||||||
/* Zero-fill by default */
|
|
||||||
out->speed = 0;
|
|
||||||
out->steer = 0;
|
|
||||||
out->voltage_mv = 0;
|
|
||||||
out->current_ma = 0;
|
|
||||||
out->temperature_c = 0;
|
|
||||||
out->fault = 0;
|
|
||||||
|
|
||||||
if (g_active_backend && g_active_backend->get_telemetry) {
|
|
||||||
g_active_backend->get_telemetry(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,127 +0,0 @@
|
|||||||
#include "esc_backend.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "stm32f7xx_hal.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hoverboard ESC Backend Implementation
|
|
||||||
*
|
|
||||||
* Adapts the Hoverboard EFeru FOC protocol to the ESC backend vtable.
|
|
||||||
* UART2: PA2=TX, PA3=RX @ 115200 baud
|
|
||||||
*
|
|
||||||
* Packet: [0xABCD] [steer:i16] [speed:i16] [checksum:u16]
|
|
||||||
* Checksum = start ^ steer ^ speed
|
|
||||||
* Speed range: -1000 to +1000
|
|
||||||
* Must send at >=50Hz or ESC times out.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define HOVERBOARD_START_FRAME 0xABCD
|
|
||||||
#define HOVERBOARD_BAUD 115200
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
|
||||||
uint16_t start;
|
|
||||||
int16_t steer;
|
|
||||||
int16_t speed;
|
|
||||||
uint16_t checksum;
|
|
||||||
} hoverboard_cmd_t;
|
|
||||||
|
|
||||||
static UART_HandleTypeDef huart2;
|
|
||||||
|
|
||||||
/* Backend vtable instance */
|
|
||||||
static const esc_backend_t hoverboard_backend;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize UART2 for hoverboard communication.
|
|
||||||
* Called once at startup via backend registration.
|
|
||||||
*/
|
|
||||||
static void hoverboard_backend_init(void) {
|
|
||||||
/* Enable clocks */
|
|
||||||
__HAL_RCC_USART2_CLK_ENABLE();
|
|
||||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
||||||
|
|
||||||
/* PA2=TX, PA3=RX, AF7 for USART2 */
|
|
||||||
GPIO_InitTypeDef gpio = {0};
|
|
||||||
gpio.Pin = GPIO_PIN_2 | GPIO_PIN_3;
|
|
||||||
gpio.Mode = GPIO_MODE_AF_PP;
|
|
||||||
gpio.Pull = GPIO_PULLUP;
|
|
||||||
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
||||||
gpio.Alternate = GPIO_AF7_USART2;
|
|
||||||
HAL_GPIO_Init(GPIOA, &gpio);
|
|
||||||
|
|
||||||
/* USART2 config */
|
|
||||||
huart2.Instance = USART2;
|
|
||||||
huart2.Init.BaudRate = HOVERBOARD_BAUD;
|
|
||||||
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
|
||||||
huart2.Init.StopBits = UART_STOPBITS_1;
|
|
||||||
huart2.Init.Parity = UART_PARITY_NONE;
|
|
||||||
huart2.Init.Mode = UART_MODE_TX_RX;
|
|
||||||
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
|
||||||
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
|
||||||
HAL_UART_Init(&huart2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send motor command via hoverboard protocol.
|
|
||||||
* Called at ~50Hz from motor_driver_update().
|
|
||||||
*/
|
|
||||||
static void hoverboard_backend_send(int16_t speed, int16_t steer) {
|
|
||||||
hoverboard_cmd_t cmd;
|
|
||||||
cmd.start = HOVERBOARD_START_FRAME;
|
|
||||||
cmd.steer = steer;
|
|
||||||
cmd.speed = speed;
|
|
||||||
cmd.checksum = cmd.start ^ cmd.steer ^ cmd.speed;
|
|
||||||
|
|
||||||
HAL_UART_Transmit(&huart2, (uint8_t *)&cmd, sizeof(cmd), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Emergency stop: send zero and disable motors.
|
|
||||||
* Hoverboard will disable outputs on repeated zero packets.
|
|
||||||
*/
|
|
||||||
static void hoverboard_backend_estop(void) {
|
|
||||||
hoverboard_backend_send(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resume after estop (optional, hoverboard auto-resumes on non-zero command).
|
|
||||||
*/
|
|
||||||
static void hoverboard_backend_resume(void) {
|
|
||||||
/* No action needed — next non-zero send will resume */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Query telemetry from hoverboard.
|
|
||||||
* Hoverboard protocol is command-only (no RX in this implementation).
|
|
||||||
* Return zero telemetry stub; future: add RX feedback.
|
|
||||||
*/
|
|
||||||
static void hoverboard_backend_get_telemetry(esc_telemetry_t *out) {
|
|
||||||
if (out) {
|
|
||||||
out->speed = 0;
|
|
||||||
out->steer = 0;
|
|
||||||
out->voltage_mv = 0;
|
|
||||||
out->current_ma = 0;
|
|
||||||
out->temperature_c = 0;
|
|
||||||
out->fault = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hoverboard backend vtable */
|
|
||||||
static const esc_backend_t hoverboard_backend = {
|
|
||||||
.init = hoverboard_backend_init,
|
|
||||||
.send = hoverboard_backend_send,
|
|
||||||
.estop = hoverboard_backend_estop,
|
|
||||||
.resume = hoverboard_backend_resume,
|
|
||||||
.get_telemetry = hoverboard_backend_get_telemetry,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public functions for backward compatibility.
|
|
||||||
* These remain for existing code that calls hoverboard_init/hoverboard_send directly.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void hoverboard_init(void) {
|
|
||||||
esc_backend_register(&hoverboard_backend);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hoverboard_send(int16_t speed, int16_t steer) {
|
|
||||||
esc_send(speed, steer);
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
#include "esc_backend.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* VESC ESC Backend Stub
|
|
||||||
*
|
|
||||||
* Placeholder implementation for FSESC 4.20 Plus (VESC-based dual ESC).
|
|
||||||
* UART: ttyTHS1 (Jetson Orin) → FC USART6 @ 921600 baud
|
|
||||||
* Protocol: pyvesc with CRC16-XModem checksum
|
|
||||||
*
|
|
||||||
* Issue #383: VESC integration (fills in this stub)
|
|
||||||
* Issue #388: ESC abstraction layer (provides this interface)
|
|
||||||
*
|
|
||||||
* TODO (Issue #383):
|
|
||||||
* - Implement vesc_init() with UART/GPIO config
|
|
||||||
* - Implement vesc_send() with pyvesc packet encoding (duty/RPM control)
|
|
||||||
* - Implement vesc_estop() to disable motor controller
|
|
||||||
* - Implement vesc_get_telemetry() to parse VESC state messages
|
|
||||||
* - Add balance mode configuration if using VESC balance app
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const esc_backend_t vesc_backend;
|
|
||||||
|
|
||||||
/* Stub implementations — no-op until #383 fills them in */
|
|
||||||
|
|
||||||
static void vesc_backend_init(void) {
|
|
||||||
/* TODO (Issue #383): Initialize UART6, configure VESC balance mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vesc_backend_send(int16_t speed, int16_t steer) {
|
|
||||||
/* TODO (Issue #383): Encode speed/steer to pyvesc packet and send via UART6 */
|
|
||||||
(void)speed;
|
|
||||||
(void)steer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vesc_backend_estop(void) {
|
|
||||||
/* TODO (Issue #383): Send VESC shutdown command to disable motors */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vesc_backend_resume(void) {
|
|
||||||
/* TODO (Issue #383): Resume from estop if needed */
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vesc_backend_get_telemetry(esc_telemetry_t *out) {
|
|
||||||
/* TODO (Issue #383): Poll/parse VESC telemetry (voltage, current, RPM, temp, fault) */
|
|
||||||
if (out) {
|
|
||||||
out->speed = 0;
|
|
||||||
out->steer = 0;
|
|
||||||
out->voltage_mv = 0;
|
|
||||||
out->current_ma = 0;
|
|
||||||
out->temperature_c = 0;
|
|
||||||
out->fault = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VESC backend vtable */
|
|
||||||
static const esc_backend_t vesc_backend = {
|
|
||||||
.init = vesc_backend_init,
|
|
||||||
.send = vesc_backend_send,
|
|
||||||
.estop = vesc_backend_estop,
|
|
||||||
.resume = vesc_backend_resume,
|
|
||||||
.get_telemetry = vesc_backend_get_telemetry,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Public function to register VESC backend.
|
|
||||||
* Called from main.c when configured with ESC_BACKEND=VESC.
|
|
||||||
*/
|
|
||||||
void vesc_backend_register_impl(void) {
|
|
||||||
esc_backend_register(&vesc_backend);
|
|
||||||
}
|
|
||||||
41
src/hoverboard.c
Normal file
41
src/hoverboard.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "hoverboard.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "stm32f7xx_hal.h"
|
||||||
|
|
||||||
|
static UART_HandleTypeDef huart2;
|
||||||
|
|
||||||
|
void hoverboard_init(void) {
|
||||||
|
/* Enable clocks */
|
||||||
|
__HAL_RCC_USART2_CLK_ENABLE();
|
||||||
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||||
|
|
||||||
|
/* PA2=TX, PA3=RX, AF7 for USART2 */
|
||||||
|
GPIO_InitTypeDef gpio = {0};
|
||||||
|
gpio.Pin = GPIO_PIN_2 | GPIO_PIN_3;
|
||||||
|
gpio.Mode = GPIO_MODE_AF_PP;
|
||||||
|
gpio.Pull = GPIO_PULLUP;
|
||||||
|
gpio.Speed = GPIO_SPEED_FREQ_HIGH;
|
||||||
|
gpio.Alternate = GPIO_AF7_USART2;
|
||||||
|
HAL_GPIO_Init(GPIOA, &gpio);
|
||||||
|
|
||||||
|
/* USART2 config */
|
||||||
|
huart2.Instance = USART2;
|
||||||
|
huart2.Init.BaudRate = HOVERBOARD_BAUD;
|
||||||
|
huart2.Init.WordLength = UART_WORDLENGTH_8B;
|
||||||
|
huart2.Init.StopBits = UART_STOPBITS_1;
|
||||||
|
huart2.Init.Parity = UART_PARITY_NONE;
|
||||||
|
huart2.Init.Mode = UART_MODE_TX_RX;
|
||||||
|
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
||||||
|
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
|
||||||
|
HAL_UART_Init(&huart2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hoverboard_send(int16_t speed, int16_t steer) {
|
||||||
|
hoverboard_cmd_t cmd;
|
||||||
|
cmd.start = HOVERBOARD_START_FRAME;
|
||||||
|
cmd.steer = steer;
|
||||||
|
cmd.speed = speed;
|
||||||
|
cmd.checksum = cmd.start ^ cmd.steer ^ cmd.speed;
|
||||||
|
|
||||||
|
HAL_UART_Transmit(&huart2, (uint8_t *)&cmd, sizeof(cmd), 5);
|
||||||
|
}
|
||||||
@ -15,7 +15,6 @@
|
|||||||
#include "i2c1.h"
|
#include "i2c1.h"
|
||||||
#include "bmp280.h"
|
#include "bmp280.h"
|
||||||
#include "mag.h"
|
#include "mag.h"
|
||||||
#include "bno055.h"
|
|
||||||
#include "jetson_cmd.h"
|
#include "jetson_cmd.h"
|
||||||
#include "jlink.h"
|
#include "jlink.h"
|
||||||
#include "ota.h"
|
#include "ota.h"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#include "motor_driver.h"
|
#include "motor_driver.h"
|
||||||
#include "esc_backend.h"
|
#include "hoverboard.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ void motor_driver_update(motor_driver_t *m,
|
|||||||
|
|
||||||
/* Emergency stop: send zero, hold latch */
|
/* Emergency stop: send zero, hold latch */
|
||||||
if (m->estop) {
|
if (m->estop) {
|
||||||
esc_send(0, 0);
|
hoverboard_send(0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ void motor_driver_update(motor_driver_t *m,
|
|||||||
if (steer > headroom) steer = headroom;
|
if (steer > headroom) steer = headroom;
|
||||||
if (steer < -headroom) steer = -headroom;
|
if (steer < -headroom) steer = -headroom;
|
||||||
|
|
||||||
esc_send((int16_t)speed, (int16_t)steer);
|
hoverboard_send((int16_t)speed, (int16_t)steer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void motor_driver_estop(motor_driver_t *m) {
|
void motor_driver_estop(motor_driver_t *m) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user