sl-firmware fa75c442a7 feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only
Archive STM32 firmware to legacy/stm32/:
- src/, include/, lib/USB_CDC/, platformio.ini, test stubs, flash_firmware.py
- test/test_battery_adc.c, test_hw_button.c, test_pid_schedule.c, test_vesc_can.c, test_can_watchdog.c
- USB_CDC_BUG.md

Rename: stm32_protocol → esp32_protocol, mamba_protocol → balance_protocol,
  stm32_cmd_node → esp32_cmd_node, stm32_cmd_params → esp32_cmd_params,
  stm32_cmd.launch.py → esp32_cmd.launch.py,
  test_stm32_protocol → test_esp32_protocol, test_stm32_cmd_node → test_esp32_cmd_node

Content cleanup across all files:
- Mamba F722S → ESP32-S3 BALANCE
- BlackPill → ESP32-S3 IO
- STM32F722/F7xx → ESP32-S3
- stm32Mode/Version/Port → esp32Mode/Version/Port
- STM32 State/Mode labels → ESP32 State/Mode
- Jetson Nano → Jetson Orin Nano Super
- /dev/stm32 → /dev/esp32
- stm32_bridge → esp32_bridge
- STM32 HAL → ESP-IDF

docs/SALTYLAB.md:
- Update "Drone FC Details" to describe ESP32-S3 BALANCE board (Waveshare ESP32-S3 Touch LCD 1.28)
- Replace verbose "Self-Balancing Control" STM32 section with brief note pointing to SAUL-TEE-SYSTEM-REFERENCE.md

TEAM.md: Update Embedded Firmware Engineer role to ESP32-S3 / ESP-IDF

No new functionality — cleanup only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 09:00:38 -04:00

141 lines
4.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* steering_pid.c — closed-loop yaw-rate PID for differential drive (Issue #616).
*
* Converts Jetson Twist.angular.z (encoded as steer * STEER_OMEGA_SCALE deg/s)
* into a differential wheel speed offset using IMU gyro Z as feedback.
*
* Anti-windup: integral clamped to ±STEER_INTEGRAL_MAX before Ki multiply.
* Rate limiter: output changes at most STEER_RAMP_RATE_PER_MS per ms so that
* a step in steering demand cannot disturb the balance PID.
*/
#include "steering_pid.h"
#include "jlink.h"
/* ---- steering_pid_init() ---- */
void steering_pid_init(steering_pid_t *s)
{
s->target_omega_dps = 0.0f;
s->actual_omega_dps = 0.0f;
s->integral = 0.0f;
s->prev_error = 0.0f;
s->output = 0;
s->enabled = true;
/* Initialize so first send_tlm call fires immediately */
s->last_tlm_ms = (uint32_t)(-(uint32_t)(1000u / (STEER_TLM_HZ > 0u ? STEER_TLM_HZ : 1u)));
}
/* ---- steering_pid_reset() ---- */
void steering_pid_reset(steering_pid_t *s)
{
s->target_omega_dps = 0.0f;
s->integral = 0.0f;
s->prev_error = 0.0f;
s->output = 0;
}
/* ---- steering_pid_set_target() ---- */
void steering_pid_set_target(steering_pid_t *s, float omega_dps)
{
if (!s->enabled) return;
s->target_omega_dps = omega_dps;
}
/* ---- steering_pid_update() ---- */
int16_t steering_pid_update(steering_pid_t *s, float actual_omega_dps, float dt)
{
if (!s->enabled || dt <= 0.0f) {
s->output = 0;
return 0;
}
s->actual_omega_dps = actual_omega_dps;
/* PID error */
float error = s->target_omega_dps - actual_omega_dps;
/* Proportional */
float p_term = STEER_KP * error;
/* Integral with anti-windup clamp */
s->integral += error * dt;
if (s->integral > STEER_INTEGRAL_MAX) s->integral = STEER_INTEGRAL_MAX;
if (s->integral < -STEER_INTEGRAL_MAX) s->integral = -STEER_INTEGRAL_MAX;
float i_term = STEER_KI * s->integral;
/* Derivative on error (avoids setpoint kick for smooth yaw changes) */
float d_term = 0.0f;
if (dt > 0.0f) {
d_term = STEER_KD * (error - s->prev_error) / dt;
}
s->prev_error = error;
/* Sum and clamp raw output */
float raw = p_term + i_term + d_term;
if (raw > (float)STEER_OUTPUT_MAX) raw = (float)STEER_OUTPUT_MAX;
if (raw < -(float)STEER_OUTPUT_MAX) raw = -(float)STEER_OUTPUT_MAX;
/* Rate limiter: bound change per step by STEER_RAMP_RATE_PER_MS * dt */
float max_step = (float)STEER_RAMP_RATE_PER_MS * (dt * 1000.0f);
float delta = raw - (float)s->output;
if (delta > max_step) delta = max_step;
if (delta < -max_step) delta = -max_step;
float limited = (float)s->output + delta;
/* Final clamp after rate limit */
if (limited > (float)STEER_OUTPUT_MAX) limited = (float)STEER_OUTPUT_MAX;
if (limited < -(float)STEER_OUTPUT_MAX) limited = -(float)STEER_OUTPUT_MAX;
s->output = (int16_t)limited;
return s->output;
}
/* ---- steering_pid_get_output() ---- */
int16_t steering_pid_get_output(const steering_pid_t *s)
{
return s->output;
}
/* ---- steering_pid_set_enabled() ---- */
void steering_pid_set_enabled(steering_pid_t *s, bool en)
{
if (!en && s->enabled) {
/* Disabling: zero out state */
s->target_omega_dps = 0.0f;
s->integral = 0.0f;
s->prev_error = 0.0f;
s->output = 0;
}
s->enabled = en;
}
/* ---- steering_pid_send_tlm() ---- */
void steering_pid_send_tlm(const steering_pid_t *s, uint32_t now_ms)
{
if (STEER_TLM_HZ == 0u) return;
uint32_t interval_ms = 1000u / STEER_TLM_HZ;
if ((now_ms - s->last_tlm_ms) < interval_ms) return;
/* Cast away const for timestamp update — only mutable field */
((steering_pid_t *)s)->last_tlm_ms = now_ms;
jlink_tlm_steering_t tlm;
/* Scale to ×10 for 0.1 deg/s resolution, clamped to int16 range */
float t = s->target_omega_dps * 10.0f;
if (t > 32767.0f) t = 32767.0f;
if (t < -32768.0f) t = -32768.0f;
tlm.target_x10 = (int16_t)t;
float a = s->actual_omega_dps * 10.0f;
if (a > 32767.0f) a = 32767.0f;
if (a < -32768.0f) a = -32768.0f;
tlm.actual_x10 = (int16_t)a;
tlm.output = s->output;
tlm.enabled = s->enabled ? 1u : 0u;
tlm._pad = 0u;
jlink_send_steering_tlm(&tlm);
}