@Athena - please examine the Mega sketch and EZBv4 script below.
Summary / expected behavior
- ARC project where ARC communicates with an Arduino Mega via an EZBv4 script over a hardware UART connection (EZB hardware UART Mega Serial3).
- Mega firmware should run the motors when Waypoint Data (CMD_WAYPOINT_DATA) is received via UART, and it should print debug text when data arrives.
Observed behavior
- After uploading the sketch to the Mega, the first Waypoint Data transmission is received and printed.
- Subsequent UART transmissions are not received or printed until the sketch is re-uploaded to the Mega.
- The motors never operate as expected when Waypoint Data is received.
Notes / context and things to verify
- The Mega firmware uses Serial3 as the ARC/EZB link (#define LINK_SERIAL Serial3).
- The EZBv4 manager script (Mega_Mgr_v3) sets UART_INDEX = 0 (hardware UART 0). Please verify the physical UART mapping between the EZB and the Mega (which EZB hardware UART is wired to the Mega's Serial3) and confirm the correct UART_INDEX to use in the EZBv4 script.
- The Mega sketch parses binary packets framed with a UART header 0xA5 and a cmd/len/payload/checksum (checksum = XOR of cmd ^ len ^ payload bytes). Please verify that the EZB manager script’s packet formation and checksum (XOR of cmd/len/payload) matches the Mega firmware protocol exactly (including the header byte and byte ordering).
- I have included both the Mega sketch (Mega_Firmware_v3) and the EZBv4 UART manager script (Mega_Mgr_v3) below.
- Request: Can you troubleshoot the Mega firmware and rewrite it as necessary? Please name the revised firmware Mega_Firmware_v4.
- Also verify the EZBv4 manager script matches the Mega protocol and rewrite it if necessary.
Thank you,
Jack
Mega_Firmware_v3
#include <AccelStepper.h>
// ======================================================
// UART / Protocol
// ======================================================
static const uint32_t BAUD = 115200;
static const uint8_t UART_HEADER = 0xA5;
// ARC/EZB link on Mega Serial3
#define LINK_SERIAL Serial3
// Debug to USB serial monitor
#define DBG_SERIAL Serial
// Commands from ARC/EZB
enum CommandId : uint8_t {
CMD_STOP_MOTORS = 0x01,
CMD_ACTUAL_BEARING = 0x03,
CMD_RIGHT_PIVOT = 0x04,
CMD_LEFT_PIVOT = 0x05,
CMD_WAYPOINT_DATA = 0x06
};
// Responses to ARC/EZB
enum ResponseId : uint8_t {
RSP_NAV_ACK = 0x10,
RSP_TOTAL_STEPS = 0x11,
RSP_DESIRED_BEARING = 0x12,
RSP_OBS_SCAN_REQUEST = 0x13,
RSP_READY = 0x14,
RSP_STATUS = 0x15,
RSP_ACK = 0x16,
RSP_NAK = 0x17
};
// ======================================================
// Stepper motors
// ======================================================
AccelStepper LeftFrontWheel(AccelStepper::DRIVER, 3, 6);
AccelStepper LeftBackWheel(AccelStepper::DRIVER, 2, 5);
AccelStepper RightFrontWheel(AccelStepper::DRIVER, 12, 13);
AccelStepper RightBackWheel(AccelStepper::DRIVER, 4, 7);
// ======================================================
// State
// ======================================================
enum MotionMode {
MODE_IDLE = 0,
MODE_TRACKING = 1,
MODE_PIVOT_RIGHT = 2,
MODE_PIVOT_LEFT = 3
};
MotionMode mode = MODE_IDLE;
bool systemReady = false;
bool motorsEnabled = false;
// ======================================================
// Leg data
// ======================================================
uint32_t pathTotalDistance = 0;
uint32_t combinedStepsDesired = 0;
uint32_t oppositeDistance = 0;
uint8_t bearingAlignment = 0;
uint16_t desiredBearing100 = 9000;
uint16_t actualBearing100 = 9000;
uint8_t trackDir = 0;
uint32_t scanIntervalSteps = 3056;
// ======================================================
// Runtime
// ======================================================
uint32_t totalStepsTaken = 0;
uint32_t lastReportedSteps = 0;
uint32_t lastDesiredBearingReportMs = 0;
uint32_t lastStatusReportMs = 0;
// ======================================================
// Motion control
// ======================================================
int wheelSpeedBase = 1600;
int leftTargetSpeed = 0;
int rightTargetSpeed = 0;
int leftCurrentSpeed = 0;
int rightCurrentSpeed = 0;
int speedRampStep = 25;
float desiredCourse = 90.0f;
float actualCourse = 90.0f;
float diffCourse = 0.0f;
bool legInfoPrinted = false;
bool actualBearingPrintedOnce = false;
bool stopPrintedOnce = false;
bool waypointLoaded = false;
// ======================================================
// RX parser
// ======================================================
uint8_t rxState = 0;
uint8_t rxCmd = 0;
uint8_t rxLen = 0;
uint8_t rxIndex = 0;
uint8_t rxChecksum = 0;
uint8_t rxPayload[64];
// ======================================================
// Helpers
// ======================================================
void debugPrint(const String& s) {
DBG_SERIAL.println(s);
}
void sendText(const String& s) {
LINK_SERIAL.println(s);
}
void sendReady() {
sendText("READY,Mega,v3");
}
void sendAck(const String& msg) {
sendText("ACK," + msg);
}
void sendNak(const String& msg) {
sendText("NAK," + msg);
}
uint8_t bytesToU16LE(const uint8_t* b) {
return 0;
}
uint16_t readU16LE(const uint8_t* b) {
return ((uint16_t)b[0]) | (((uint16_t)b[1]) << 8);
}
uint32_t readU32LE(const uint8_t* b) {
return ((uint32_t)b[0]) |
(((uint32_t)b[1]) << 8) |
(((uint32_t)b[2]) << 16) |
(((uint32_t)b[3]) << 24);
}
void sendBinaryPacket(uint8_t cmd, const uint8_t* payload, uint8_t len) {
uint8_t cs = cmd ^ len;
for (uint8_t i = 0; i < len; i++) cs ^= payload[i];
LINK_SERIAL.write(UART_HEADER);
LINK_SERIAL.write(cmd);
LINK_SERIAL.write(len);
for (uint8_t i = 0; i < len; i++) {
LINK_SERIAL.write(payload[i]);
}
LINK_SERIAL.write(cs);
}
void printLegInfoOnce() {
if (legInfoPrinted) return;
debugPrint("MEGA leg info received:");
debugPrint(" pathTotalDistance = " + String(pathTotalDistance));
debugPrint(" combinedStepsDesired = " + String(combinedStepsDesired));
debugPrint(" oppositeDistance = " + String(oppositeDistance));
debugPrint(" bearingAlignment = " + String(bearingAlignment));
debugPrint(" desiredBearing100 = " + String(desiredBearing100));
debugPrint(" actualBearing100 = " + String(actualBearing100));
debugPrint(" trackDir = " + String(trackDir));
debugPrint(" scanIntervalSteps = " + String(scanIntervalSteps));
legInfoPrinted = true;
}
void printActualBearingOnce(uint16_t bearing100) {
if (!actualBearingPrintedOnce) {
debugPrint("MEGA actual bearing received = " + String(bearing100));
actualBearingPrintedOnce = true;
}
}
void printStopOnce(const String& src) {
if (!stopPrintedOnce) {
debugPrint("MEGA STOP: " + src);
stopPrintedOnce = true;
}
}
void reportDesiredBearingIfChangedBy1(uint16_t newBearing100) {
static int lastReportedDeg = -9999;
int deg = (int)(newBearing100 / 100);
if (lastReportedDeg == -9999 || abs(deg - lastReportedDeg) >= 1) {
uint8_t payload[2];
payload[0] = newBearing100 & 0xFF;
payload[1] = (newBearing100 >> 8) & 0xFF;
sendBinaryPacket(RSP_DESIRED_BEARING, payload, 2);
debugPrint("MEGA desired bearing reported = " + String(newBearing100));
lastReportedDeg = deg;
}
}
void reportTotalStepsIfChanged() {
if (totalStepsTaken != lastReportedSteps) {
uint8_t payload[4];
payload[0] = totalStepsTaken & 0xFF;
payload[1] = (totalStepsTaken >> 8) & 0xFF;
payload[2] = (totalStepsTaken >> 16) & 0xFF;
payload[3] = (totalStepsTaken >> 24) & 0xFF;
sendBinaryPacket(RSP_TOTAL_STEPS, payload, 4);
lastReportedSteps = totalStepsTaken;
}
}
void stopMotors() {
leftTargetSpeed = 0;
rightTargetSpeed = 0;
leftCurrentSpeed = 0;
rightCurrentSpeed = 0;
motorsEnabled = false;
mode = MODE_IDLE;
LeftFrontWheel.setSpeed(0);
LeftBackWheel.setSpeed(0);
RightFrontWheel.setSpeed(0);
RightBackWheel.setSpeed(0);
LeftFrontWheel.runSpeed();
LeftBackWheel.runSpeed();
RightFrontWheel.runSpeed();
RightBackWheel.runSpeed();
}
void applyMotorSpeeds() {
LeftFrontWheel.setSpeed(leftCurrentSpeed);
LeftBackWheel.setSpeed(rightCurrentSpeed);
RightFrontWheel.setSpeed(rightCurrentSpeed);
RightBackWheel.setSpeed(leftCurrentSpeed);
LeftFrontWheel.runSpeed();
LeftBackWheel.runSpeed();
RightFrontWheel.runSpeed();
RightBackWheel.runSpeed();
}
void rampTowardTargets() {
if (leftCurrentSpeed < leftTargetSpeed) {
leftCurrentSpeed += speedRampStep;
if (leftCurrentSpeed > leftTargetSpeed) leftCurrentSpeed = leftTargetSpeed;
} else if (leftCurrentSpeed > leftTargetSpeed) {
leftCurrentSpeed -= speedRampStep;
if (leftCurrentSpeed < leftTargetSpeed) leftCurrentSpeed = leftTargetSpeed;
}
if (rightCurrentSpeed < rightTargetSpeed) {
rightCurrentSpeed += speedRampStep;
if (rightCurrentSpeed > rightTargetSpeed) rightCurrentSpeed = rightTargetSpeed;
} else if (rightCurrentSpeed > rightTargetSpeed) {
rightCurrentSpeed -= speedRampStep;
if (rightCurrentSpeed < rightTargetSpeed) rightCurrentSpeed = rightTargetSpeed;
}
}
void computeDesiredCourse() {
desiredCourse = desiredBearing100 / 100.0f;
}
void updateMotionControl() {
if (!motorsEnabled) {
stopMotors();
return;
}
computeDesiredCourse();
actualCourse = actualBearing100 / 100.0f;
diffCourse = actualCourse - desiredCourse;
int correction = (int)(diffCourse * 20.0f);
leftTargetSpeed = wheelSpeedBase - correction;
rightTargetSpeed = wheelSpeedBase + correction;
if (leftTargetSpeed < wheelSpeedBase - 400) leftTargetSpeed = wheelSpeedBase - 400;
if (leftTargetSpeed > wheelSpeedBase + 400) leftTargetSpeed = wheelSpeedBase + 400;
if (rightTargetSpeed < wheelSpeedBase - 400) rightTargetSpeed = wheelSpeedBase - 400;
if (rightTargetSpeed > wheelSpeedBase + 400) rightTargetSpeed = wheelSpeedBase + 400;
rampTowardTargets();
applyMotorSpeeds();
}
void handleWaypointPacket(const uint8_t* p, uint8_t len) {
if (len != 22) {
sendNak("WAYPOINT_LEN");
return;
}
pathTotalDistance = readU32LE(&p[0]);
combinedStepsDesired = readU32LE(&p[4]);
oppositeDistance = readU32LE(&p[8]);
bearingAlignment = p[12];
desiredBearing100 = readU16LE(&p[13]);
actualBearing100 = readU16LE(&p[15]);
trackDir = p[17];
scanIntervalSteps = readU32LE(&p[18]);
printLegInfoOnce();
sendAck("WAYPOINT");
}
void handleBinaryPacket(uint8_t cmd, const uint8_t* payload, uint8_t len) {
switch (cmd) {
case CMD_STOP_MOTORS:
printStopOnce("received STOP command");
stopMotors();
sendAck("STOP");
break;
case CMD_ACTUAL_BEARING:
if (len != 2) {
sendNak("ACTUAL_BEARING_LEN");
return;
}
actualBearing100 = readU16LE(payload);
printActualBearingOnce(actualBearing100);
break;
case CMD_RIGHT_PIVOT:
if (len != 2) {
sendNak("RIGHT_PIVOT_LEN");
return;
}
combinedStepsDesired = readU16LE(payload);
mode = MODE_PIVOT_RIGHT;
motorsEnabled = true;
sendAck("RIGHT_PIVOT");
break;
case CMD_LEFT_PIVOT:
if (len != 2) {
sendNak("LEFT_PIVOT_LEN");
return;
}
combinedStepsDesired = readU16LE(payload);
mode = MODE_PIVOT_LEFT;
motorsEnabled = true;
sendAck("LEFT_PIVOT");
break;
case CMD_WAYPOINT_DATA:
handleWaypointPacket(payload, len);
break;
default:
sendNak("UNKNOWN_CMD");
break;
}
}
void processIncoming() {
while (LINK_SERIAL.available() > 0) {
uint8_t b = (uint8_t)LINK_SERIAL.read();
if (rxState == 0) {
if (b == UART_HEADER) rxState = 1;
continue;
}
if (rxState == 1) {
rxCmd = b;
rxChecksum = rxCmd;
rxState = 2;
continue;
}
if (rxState == 2) {
rxLen = b;
rxChecksum ^= rxLen;
rxIndex = 0;
if (rxLen > sizeof(rxPayload)) {
rxState = 0;
sendNak("LEN_OVF");
} else {
rxState = (rxLen == 0) ? 4 : 3;
}
continue;
}
if (rxState == 3) {
rxPayload[rxIndex++] = b;
rxChecksum ^= b;
if (rxIndex >= rxLen) rxState = 4;
continue;
}
if (rxState == 4) {
if (b == rxChecksum) {
handleBinaryPacket(rxCmd, rxPayload, rxLen);
} else {
sendNak("CS");
}
rxState = 0;
rxCmd = 0;
rxLen = 0;
rxIndex = 0;
rxChecksum = 0;
continue;
}
}
}
// ======================================================
// Text handling
// ======================================================
String textLine = "";
void processTextLine(const String& line) {
String s = line;
s.trim();
s.toUpperCase();
if (s == "HELLO") {
systemReady = true;
sendReady();
return;
}
if (s == "STATUS?") {
String msg = "STATUS,";
msg += (motorsEnabled ? "RUNNING" : "IDLE");
msg += ",STEPS=" + String(totalStepsTaken);
msg += ",MODE=" + String((int)mode);
sendText(msg);
return;
}
if (s == "START") {
motorsEnabled = true;
mode = MODE_TRACKING;
sendAck("START");
return;
}
if (s == "STOP") {
printStopOnce("received text STOP");
stopMotors();
sendAck("STOP");
return;
}
sendNak("UNKNOWN_TEXT");
}
void processTextSerial() {
while (LINK_SERIAL.available() > 0) {
char c = (char)LINK_SERIAL.read();
if (c == '\n') {
if (textLine.length() > 0) {
processTextLine(textLine);
textLine = "";
}
} else if (c != '\r') {
textLine += c;
}
}
}
// ======================================================
// Setup / loop
// ======================================================
void setup() {
DBG_SERIAL.begin(BAUD);
LINK_SERIAL.begin(BAUD);
LeftFrontWheel.setMaxSpeed(wheelSpeedBase * 2);
LeftBackWheel.setMaxSpeed(wheelSpeedBase * 2);
RightFrontWheel.setMaxSpeed(wheelSpeedBase * 2);
RightBackWheel.setMaxSpeed(wheelSpeedBase * 2);
sendReady();
debugPrint("Mega v3 started");
}
void loop() {
processIncoming();
processTextSerial();
if (motorsEnabled) {
updateMotionControl();
totalStepsTaken = (uint32_t)(abs(LeftFrontWheel.currentPosition()) + abs(RightFrontWheel.currentPosition()));
reportTotalStepsIfChanged();
} else {
stopMotors();
}
if (millis() - lastDesiredBearingReportMs > 500) {
reportDesiredBearingIfChangedBy1(desiredBearing100);
lastDesiredBearingReportMs = millis();
}
delay(1);
}
EZB Mega_Mgr_v3
var UART_INDEX = 0; // Mega UART0
var UART_BAUD = 115200;
var UART_HEADER = 0xA5;
var running = true;
var megaReady = false;
var lastHelloMs = 0;
var lastStatusMs = 0;
// -------------------------
// Command IDs
// -------------------------
var CMD_STOP_MOTORS = 0x01;
var CMD_ACTUAL_BEARING = 0x03;
var CMD_RIGHT_PIVOT = 0x04;
var CMD_LEFT_PIVOT = 0x05;
var CMD_WAYPOINT_DATA = 0x06;
// -------------------------
// Response IDs
// -------------------------
var RSP_NAV_ACK = 0x10;
var RSP_TOTAL_STEPS = 0x11;
var RSP_DESIRED_BEARING = 0x12;
var RSP_OBS_SCAN_REQUEST = 0x13;
var RSP_READY = 0x14;
var RSP_STATUS = 0x15;
var RSP_ACK = 0x16;
var RSP_NAK = 0x17;
// -------------------------
// RX parser
// -------------------------
var rxState = 0;
var rxCmd = 0;
var rxLen = 0;
var rxIndex = 0;
var rxPayload = [];
var rxChecksum = 0;
// -------------------------
// Helpers
// -------------------------
function safeInt(v, def) {
var n = parseInt(v);
if (isNaN(n)) return def;
return n;
}
function clamp(v, min, max) {
if (v < min) return min;
if (v > max) return max;
return v;
}
function u16ToBytes(value) {
value = value & 0xFFFF;
return [value & 0xFF, (value >> 8) & 0xFF];
}
function u32ToBytes(value) {
value = value >>> 0;
return [
value & 0xFF,
(value >> 8) & 0xFF,
(value >> 16) & 0xFF,
(value >> 24) & 0xFF
];
}
function bytesToU16LE(b0, b1) {
return (b0 & 0xFF) | ((b1 & 0xFF) << 8);
}
function bytesToU32LE(b0, b1, b2, b3) {
return (b0 & 0xFF) |
((b1 & 0xFF) << 8) |
((b2 & 0xFF) << 16) |
((b3 & 0xFF) << 24);
}
function checksumXor(cmd, len, payload) {
var c = (cmd ^ len) & 0xFF;
for (var i = 0; i < payload.length; i++) {
c ^= (payload[i] & 0xFF);
}
return c & 0xFF;
}
function sendPacket(cmd, payload) {
var len = payload.length & 0xFF;
var checksum = checksumXor(cmd, len, payload);
UART.hardwareUartWrite(UART_INDEX, [UART_HEADER, cmd, len]);
if (payload.length > 0) {
UART.hardwareUartWrite(UART_INDEX, payload);
}
UART.hardwareUartWrite(UART_INDEX, [checksum]);
}
function requestHello() {
// If your Mega firmware supports it, add a HELLO/READY handshake there too.
// For now this is a logical startup marker in ARC.
megaReady = false;
lastHelloMs = (new Date()).getTime();
print("TX: HELLO requested");
}
function requestStatus() {
// If your Mega firmware supports STATUS? add a command ID for it.
// For now this is a placeholder to match the Teensy manager style.
lastStatusMs = (new Date()).getTime();
print("TX: STATUS requested");
}
function sendStopMotors() {
sendPacket(CMD_STOP_MOTORS, []);
print("TX: STOP MOTORS");
}
function sendActualBearing() {
var bearing100 = safeInt(getVar("$actualBearing100", 9000), 9000);
bearing100 = clamp(bearing100, 0, 18000);
sendPacket(CMD_ACTUAL_BEARING, u16ToBytes(bearing100));
print("TX: ACTUAL BEARING x100 = " + bearing100);
}
function sendWaypointData() {
var pathTotalDistance = safeInt(getVar("$pathTotalDistance", 0), 0) >>> 0;
var combinedStepsDesired = safeInt(getVar("$combinedStepsDesired", 0), 0) >>> 0;
var oppositeDistance = safeInt(getVar("$oppositeDistance", 0), 0) >>> 0;
var bearingAlignment = safeInt(getVar("$bearingAlignment", 0), 0) & 0xFF;
var trackDir = safeInt(getVar("$trackDir", 0), 0);
trackDir = (trackDir === 0) ? 0 : 1;
var desiredBearing100 = clamp(safeInt(getVar("$desiredBearing100", 9000), 9000), 0, 18000);
var actualBearing100 = clamp(safeInt(getVar("$actualBearing100", 9000), 9000), 0, 18000);
var scanIntervalSteps = safeInt(getVar("$scanIntervalSteps", 3056), 3056) >>> 0;
setVar("$desiredBearing100", desiredBearing100);
setVar("$actualBearing100", actualBearing100);
var payload = [];
payload = payload.concat(u32ToBytes(pathTotalDistance));
payload = payload.concat(u32ToBytes(combinedStepsDesired));
payload = payload.concat(u32ToBytes(oppositeDistance));
payload.push(bearingAlignment);
payload = payload.concat(u16ToBytes(desiredBearing100));
payload = payload.concat(u16ToBytes(actualBearing100));
payload.push(trackDir);
payload = payload.concat(u32ToBytes(scanIntervalSteps));
if (payload.length !== 22) {
print("Waypoint payload length error: " + payload.length);
return;
}
sendPacket(CMD_WAYPOINT_DATA, payload);
print("TX: WAYPOINT DATA");
}
function sendPivot(cmd, name) {
var steps = safeInt(getVar("$pivotSteps", 0), 0) >>> 0;
var payload = u16ToBytes(steps);
sendPacket(cmd, payload);
print("TX: " + name + " steps=" + steps);
}
function sendRightPivot() {
sendPivot(CMD_RIGHT_PIVOT, "RIGHT PIVOT");
}
function sendLeftPivot() {
sendPivot(CMD_LEFT_PIVOT, "LEFT PIVOT");
}
function requestObstacleScan() {
if (getVar("$obsScanActive", 0) == 1) {
print("RX: OBSTACLE SCAN REQUEST ignored (scan already active)");
return;
}
setVar("$obsScanRequested", 1);
setVar("$obsScanActive", 1);
print("RX: OBSTACLE SCAN REQUEST -> $obsScanRequested=1, $obsScanActive=1");
}
function handleRxPacket(cmd, payload) {
if (cmd == RSP_READY) {
megaReady = true;
print("RX: MEGA READY");
return;
}
if (cmd == RSP_ACK) {
print("RX: ACK");
return;
}
if (cmd == RSP_NAK) {
print("RX: NAK");
return;
}
if (cmd == RSP_NAV_ACK) {
print("RX: NAV ACK");
setVar("$navAckReceived", 1);
return;
}
if (cmd == RSP_TOTAL_STEPS) {
if (payload.length == 4) {
var steps = bytesToU32LE(payload[0], payload[1], payload[2], payload[3]);
setVar("$totalStepsTaken", steps);
setVar("$legComplete", 1);
print("RX: TOTAL STEPS = " + steps);
}
return;
}
if (cmd == RSP_DESIRED_BEARING) {
if (payload.length == 2) {
var bearing100 = bytesToU16LE(payload[0], payload[1]);
setVar("$desiredBearing100", bearing100);
print("RX: DESIRED BEARING x100 = " + bearing100);
}
return;
}
if (cmd == RSP_OBS_SCAN_REQUEST) {
requestObstacleScan();
return;
}
print("RX: Unknown cmd=" + cmd + " len=" + payload.length);
}
function processIncomingBytes() {
var available = UART.hardwareUartAvailable(UART_INDEX);
while (available > 0) {
var b = UART.hardwareUartRead(UART_INDEX, 1)[0] & 0xFF;
available--;
if (rxState == 0) {
if (b == UART_HEADER) rxState = 1;
continue;
}
if (rxState == 1) {
rxCmd = b;
rxChecksum = rxCmd;
rxState = 2;
continue;
}
if (rxState == 2) {
rxLen = b;
rxChecksum ^= rxLen;
rxPayload = [];
rxIndex = 0;
rxState = (rxLen == 0) ? 4 : 3;
continue;
}
if (rxState == 3) {
rxPayload.push(b);
rxChecksum ^= b;
rxIndex++;
if (rxIndex >= rxLen) rxState = 4;
continue;
}
if (rxState == 4) {
var cs = b & 0xFF;
if (cs == (rxChecksum & 0xFF)) {
handleRxPacket(rxCmd, rxPayload);
} else {
print("RX checksum error. cmd=" + rxCmd + " expected=" + (rxChecksum & 0xFF) + " got=" + cs);
}
rxState = 0;
rxCmd = 0;
rxLen = 0;
rxIndex = 0;
rxPayload = [];
rxChecksum = 0;
continue;
}
}
}
print("Mega UART Manager started");
UART.initHardwareUart(UART_INDEX, UART_BAUD);
requestHello();
sleep(200);
requestStatus();
while (true) {
if (getVar("$sendWaypointNow", 0) == 1 && getVar("$waypointSent", 0) == 0) {
sendWaypointData();
setVar("$sendWaypointNow", 0);
setVar("$waypointSent", 1);
}
if (getVar("$sendStopNow", 0) == 1 && getVar("$stopSent", 0) == 0) {
sendStopMotors();
setVar("$sendStopNow", 0);
setVar("$stopSent", 1);
}
if (getVar("$sendActualBearingNow", 0) == 1) {
sendActualBearing();
setVar("$sendActualBearingNow", 0);
}
if (getVar("$sendRightPivotNow", 0) == 1) {
sendRightPivot();
setVar("$sendRightPivotNow", 0);
}
if (getVar("$sendLeftPivotNow", 0) == 1) {
sendLeftPivot();
setVar("$sendLeftPivotNow", 0);
}
processIncomingBytes();
sleep(20);
}

Yes - your interpretation is correct.
1) The
motorEnabledtypo was my mistakeYou fixed the right thing. In
MEGA_FIRMWARE_v5, the state variable should bemotorsEnabledeverywhere. Thanks for catching that.2) About the checksum error
A checksum error means the Mega manager received a packet whose computed checksum did not match the checksum byte that arrived at the end of the packet.
That does not mean ARC is sending a STOP command.
It means one of these happened:
In your log:
That means:
17decimal =0x11=RSP_TOTAL_STEPS0x410x26So yes, MEGA_FIRMWARE is sending step telemetry, and MEGA_MGR_v5 is trying to parse it.
3) Why this happened
You said this is not intended:
That means the current
RSP_TOTAL_STEPStraffic is too much.So the fix is simple:
4) What MEGA_MGR should do
You described the manager perfectly:
So I agree: MEGA_MGR_v5 should be simplified further.
Manager responsibilities:
5) What I recommend changing now
On the Mega side
Change
MEGA_FIRMWARE_v5so it:RSP_TOTAL_STEPScontinuouslyRSP_NAV_ACKRSP_STATUSRSP_DESIRED_BEARINGRSP_OBS_SCAN_REQUESTRSP_ACK/RSP_NAKOn the manager side
Remove handling that expects step telemetry unless you really want it later.
MEGA_MGR_v6
Below is a simplified bridge-only manager. It forwards packets and does not try to monitor steps.
6) Answering your specific questions
1. Is MEGA_FIRMWARE_v5 sending number of steps as it loops to MEGA_MGR_v5?
Yes, it appears it was.
That is what caused the
RSP_TOTAL_STEPStraffic and the checksum error messages.If you want step count to remain local, we should remove that packet transmission except on special trigger events.
2. What is a checksum error and is it causing an early STOP?
A checksum error means the packet bytes did not match their checksum.
It is not a STOP command.
It can cause the manager to ignore the packet, but it should not itself stop the robot unless your script is explicitly reacting to it.
7) About the Teensy code you attached
Thank you for including it. I can review it next, but I want to stay on-topic and finish the Mega path first since you asked to fix the bridge.
That said, I already see one important architectural point from your Teensy notes:
That separation is clean and makes sense.
8) My recommendation
Use:
If you want, I can next do one of these:
If you’d like, I can do the Mega firmware cleanup next and provide a true MEGA_FIRMWARE_v6 that matches your intended behavior exactly.
@Athena. Thank you for reevaluating MEGA_Firmware_v5 and MEGA_MGR_v5.
When I run MEGA_FIRMWARE_v5 with MEGA_MGR _v6, the following happens: (screen shot of Print on MEGA_MGR_v6)
As you can see it continues to checksum error, which I believe is leading to the WI-FI disconnect.
I believe you were right stating, "1. Is MEGA_FIRMWARE_v5 sending number of steps as it loops to MEGA_MGR_v5?" I made the following change to MEGA_FIRMWARE_v5:
When MEGA_FIRMWARE_v5 stops calling for 'reportTotalStepsIfChanged()', MEGA_MGR_v6 runs as it should(Screen shot PRINT):
Of course no Step totals were counted and this is not desirable, but by stopping 'if changed' seem to fix the onslaught of STEP data going to MEGA_MGR_v6.
Here's what I am requesting:
As you rewrite MEGA_FIRMWARE, please enable only the following parameters: Let's call the new MEGA_FIRMWARE_v6.
2. A rewrite of MEGA_MGR_v6 to match the capabilities listed above of MEGA_FIRMWARE. Let's call the new MEGA_MGR_ v7.
Thank you very much. Jack
Absolutely - and yes, the checksum flood you saw is consistent with MEGA_FIRMWARE sending telemetry too frequently for the current bridge design.
What’s happening
The
RSP_TOTAL_STEPSpacket is still being emitted often enough that the ARC-side manager keeps parsing it and eventually gets out of sync with the stream. That can lead to:So your conclusion is correct: the step packets need to be suppressed except on a STOP event.
Your requested behavior
You want:
MEGA_FIRMWARE_v6
MEGA_MGR_v7
That is the right simplification.
Important note about
RSP_STATUSand step packetsFor MEGA_MGR_v7, I recommend this rule:
And for the Mega:
MEGA_FIRMWARE_v6
Below is a cleaner rewrite based on your requirements.
MEGA_MGR_v7
This one is a bridge only. It forwards commands and packets, and does not try to interpret step totals or control the robot.
What this changes
Mega
Manager
About your Teensy files
Yes, I can review them, but I do not have any hidden or private "latest" files beyond what you pasted here. If you want, I can now help align the Teensy protocol to this bridge model.
If you want to continue, I recommend the next step be:
If you’d like, I can also make a MEGA_FIRMWARE_v6.1 that adds a tiny
LEG_COMPLETEresponse so ARC can distinguish "stop because commanded" vs "stop because leg ended."@Athena. Thank you.