#pragma once #include // ===================================================================== // Remote handset config (Teensy 4.1). Everything here is a placeholder // until checked against your real wiring and parts - see the BENCH notes. // Radio address/channel/rate/PA/payload size are NOT here: they live in // shared/HexapodProtocol so they can't drift from the robot. // ===================================================================== // ---- Loop rate ---- // Must be >= the robot's CONTROL_HZ (60) so every robot control tick sees a // fresh packet. 100 Hz gives margin for the odd dropped packet. constexpr float TX_HZ = 100.0f; // ---- Radio (nRF24L01) on SPI0: MOSI 11, MISO 12, SCK 13 ---- // BENCH: placeholder CE/CSN pins - match your wiring. constexpr uint8_t RADIO_CE_PIN = 9; constexpr uint8_t RADIO_CSN_PIN = 10; // Auto-retransmit: (delay units of 250us, count). Kept short on purpose - a // newer packet replaces a lost one 10 ms later anyway, and write() blocks for // the whole retry sequence. Worst case here is ~4 attempts x ~1.7 ms. constexpr uint8_t RADIO_RETRY_DELAY = 1; constexpr uint8_t RADIO_RETRY_COUNT = 3; // No acks for this long -> remote considers the link lost and disarms itself, // mirroring the robot's LINK_TIMEOUT_SEC (0.3 s) failsafe, so the robot can't // spring back up on its own when the link returns. constexpr uint32_t LINK_LOST_MS = 300; // ---- Joysticks: 2 x 3-axis analog potentiometer sticks ---- // Logical axis order used everywhere in the remote code. enum StickAxis : uint8_t { L_X = 0, L_Y, L_TWIST, R_X, R_Y, R_TWIST, NUM_AXES }; // BENCH: placeholder pins. A4/A5 (18/19) are skipped because they're the I2C // pins the MPU6050 uses. constexpr uint8_t STICK_PINS[NUM_AXES] = { A0, A1, A2, A3, A6, A7 }; // Each logical axis must end up: X + = pushed RIGHT, Y + = pushed FORWARD // (away from you), TWIST + = rotated COUNTERCLOCKWISE seen from above. // BENCH: flip any axis that reads the wrong way on the serial 'p' status dump. constexpr bool STICK_INVERT[NUM_AXES] = { false, false, false, false, false, false }; constexpr int ADC_BITS = 12; // 0..4095 constexpr int ADC_AVERAGING = 8; // hardware averaging per analogRead() // Fallback calibration used until you run the on-device sweep calibration // (which is saved to EEPROM and overrides these). // BENCH: typical pot sticks don't use the full electrical range - run the // sweep calibration once, then optionally paste the printed values here. constexpr int16_t STICK_DEFAULT_MIN = 200; constexpr int16_t STICK_DEFAULT_CENTER = 2048; constexpr int16_t STICK_DEFAULT_MAX = 3900; // At power-on the resting position of each axis is re-captured as its center // (pots drift a little with temperature). Rejected if a stick is visibly // deflected, i.e. further than this from the stored center (ADC counts). constexpr int16_t CENTER_CAPTURE_TOLERANCE = 250; // A sweep calibration is rejected unless every axis travels at least this // far on both sides of center (ADC counts) - catches "forgot to move a stick". constexpr int16_t CAL_MIN_HALF_SPAN = 600; // Deadzone as a fraction of full deflection; output is rescaled so motion // starts smoothly from 0 at the deadzone edge instead of jumping. constexpr float STICK_DEADZONE[NUM_AXES] = { 0.06f, 0.06f, 0.10f, 0.06f, 0.06f, 0.10f }; // 0 = linear, 1 = fully cubic. A bit of expo gives fine control near center. constexpr float STICK_EXPO[NUM_AXES] = { 0.25f, 0.25f, 0.30f, 0.20f, 0.20f, 0.20f }; // One-pole low-pass on raw ADC counts (1 = no filtering). Pots are noisy. constexpr float STICK_FILTER_ALPHA = 0.5f; // ---- Remote IMU: MPU6050 on I2C (Wire: SDA 18, SCL 19) ---- constexpr uint8_t IMU_ADDR = 0x68; // 0x69 if AD0 is pulled high // Mounting remap: which chip axis (0=X,1=Y,2=Z) and sign gives each handset // axis. Handset frame: +X = away from you, +Y = your left, +Z = up. // BENCH: with the defaults the chip is assumed flat, component side up, its // X arrow pointing away from you. Verify with the serial 'p' dump: tipping // the far edge down must read +pitch, dipping the right side must read +roll. constexpr uint8_t IMU_AXIS_FROM_CHIP[3] = { 0, 1, 2 }; constexpr int8_t IMU_AXIS_SIGN[3] = { +1, +1, +1 }; constexpr float IMU_ALPHA = 0.98f; // complementary filter, same as the robot constexpr int IMU_GYRO_BIAS_SAMPLES = 200; // at boot; hold the remote still // Handset tilt -> CmdPacket.remote_roll/pitch. This many degrees of tilt away // from the zeroed "level" pose = full scale (1000); the robot then scales // full scale to its own MAX_TILT_DEG. constexpr float REMOTE_TILT_FULL_SCALE_DEG = 30.0f; constexpr float REMOTE_TILT_DEADZONE_DEG = 2.0f; // ignore hand tremor around level // Toggling "remote gyro" fades the tilt in/out at this rate (fraction/s) // instead of stepping it. The robot rate-limits pose as well; this just // keeps the flag change itself from being a hard edge. constexpr float REMOTE_TILT_FADE_PER_SEC = 2.0f; // ---- Operator setpoints ---- constexpr uint8_t SPEED_SCALE_DEFAULT = 128; constexpr float SPEED_SCALE_RATE_PER_SEC = 255.0f; // slider jumps ramp over <= 1 s (robot doesn't smooth twist) constexpr uint8_t SPEED_SCALE_STEP = 25; // serial console +/- step // Standing height slider -> CmdPacket.body_height (-1000..1000, 0 = the // robot's default). No smoothing here: the robot rate-limits height itself. constexpr int16_t HEIGHT_STEP = 100; // serial console [ / ] step // FLAG_WALK stays set this long after the left stick returns to center, so // hovering at the deadzone edge doesn't chatter STAND <-> WALKING. constexpr uint32_t WALK_LINGER_MS = 250; // Arming is refused unless every stick axis is within this of center // (post-deadzone, -1000..1000 scale), so the robot never arms mid-command. constexpr int16_t ARM_CENTER_TOLERANCE = 50; // ---- Nextion touchscreen on Serial2 (RX2 = pin 7, TX2 = pin 8) ---- #define NEXTION_SERIAL Serial2 // BENCH: Nextion ships at 9600. The HMI's Program.s must set `bauds=115200` // (see remote/NEXTION.md) or change this to match. constexpr uint32_t NEXTION_BAUD = 115200; constexpr uint32_t NEXTION_FULL_REFRESH_MS = 2000; // re-push everything periodically (self-heals after a display reset) constexpr uint32_t NEXTION_LINK_REFRESH_MS = 250; // link-quality text update rate constexpr uint32_t STATUS_MESSAGE_MS = 2500; // how long transient status messages stay up