mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
hardware test complete
This commit is contained in:
@@ -11,4 +11,4 @@ on each roomba:
|
|||||||
- USB wifi card
|
- USB wifi card
|
||||||
- microphone
|
- microphone
|
||||||
- speaker
|
- speaker
|
||||||
- MAYBE a master relay which can be turned off programatically to save the roomba from discharging
|
- MAYBE a master relay which can be turned off programatically to save the roomba from discharging. based on battery voltage plus urgent battery #?
|
||||||
@@ -10,6 +10,8 @@ this event will be sent all of the module data at once, in JSON
|
|||||||
|
|
||||||
split each JSON element to the UI element functions
|
split each JSON element to the UI element functions
|
||||||
|
|
||||||
|
one single system for loading and saving user settings
|
||||||
|
|
||||||
|
|
||||||
## esp-server comms
|
## esp-server comms
|
||||||
|
|
||||||
@@ -19,6 +21,6 @@ rover's name
|
|||||||
enable / disable for each motor
|
enable / disable for each motor
|
||||||
camera IP address
|
camera IP address
|
||||||
battery info (for different battery behaviors):
|
battery info (for different battery behaviors):
|
||||||
full number
|
- full number
|
||||||
warn number
|
- warn number
|
||||||
urgent number
|
- urgent number
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[env:esp32dev]
|
[env:esp32s3]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
board = esp32dev
|
board = esp32-s3-devkitc-1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|
||||||
|
|||||||
+108
-36
@@ -1,59 +1,131 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
// Use two GPIOs with onboard-friendly defaults; adjust to match your dev kit.
|
// --- Hardware mapping -------------------------------------------------------
|
||||||
constexpr gpio_num_t LED1_PIN = GPIO_NUM_2; // Often labeled "LED_BUILTIN".
|
// Adjust these pins to match how your level shifter connects the ESP32 to the Roomba.
|
||||||
constexpr gpio_num_t LED2_PIN = GPIO_NUM_4;
|
constexpr int ROBO_UART_RX = 16; // ESP32 pin receiving Roomba TX (ROI pin 4).
|
||||||
|
constexpr int ROBO_UART_TX = 17; // ESP32 pin driving Roomba RX (ROI pin 3).
|
||||||
|
constexpr gpio_num_t ROBO_BRC_PIN = GPIO_NUM_5; // GPIO pulsing the BRC line (ROI pin 5).
|
||||||
|
|
||||||
constexpr TickType_t LED1_DELAY = pdMS_TO_TICKS(250); // 4 Hz blink.
|
// FreeRTOS cadences (1 Hz pulse, 150 ms low to ensure Roomba notices).
|
||||||
constexpr TickType_t LED2_DELAY = pdMS_TO_TICKS(700); // ~1.4 Hz blink.
|
constexpr TickType_t BRC_PERIOD = pdMS_TO_TICKS(1000);
|
||||||
|
constexpr TickType_t BRC_LOW_PULSE = pdMS_TO_TICKS(150);
|
||||||
|
|
||||||
// FreeRTOS tasks must have C linkage-compatible signatures.
|
// Simple helper to send an Open Interface command over UART.
|
||||||
void ledTask(void *parameter) {
|
void sendRoombaCommand(std::initializer_list<uint8_t> bytes) {
|
||||||
const gpio_num_t pin = static_cast<gpio_num_t>(reinterpret_cast<intptr_t>(parameter));
|
Serial1.write(bytes.begin(), bytes.size());
|
||||||
const TickType_t delay = (pin == LED1_PIN) ? LED1_DELAY : LED2_DELAY;
|
Serial1.flush(); // Ensure command clears the UART FIFO before proceeding.
|
||||||
|
}
|
||||||
|
|
||||||
pinMode(pin, OUTPUT);
|
void brcTask(void * /*parameter*/) {
|
||||||
|
|
||||||
// Align the first toggle with system tick so the cadence stays consistent.
|
|
||||||
TickType_t nextWake = xTaskGetTickCount();
|
TickType_t nextWake = xTaskGetTickCount();
|
||||||
|
uint32_t pulseCount = 0;
|
||||||
|
|
||||||
bool state = false;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
digitalWrite(pin, state ? HIGH : LOW);
|
// Idle high, pulse low to reset the five-minute sleep timer.
|
||||||
state = !state;
|
Serial.printf("[BRC] Pulse #%lu: pulling low\n", static_cast<unsigned long>(pulseCount));
|
||||||
|
gpio_set_level(ROBO_BRC_PIN, 0);
|
||||||
|
vTaskDelay(BRC_LOW_PULSE);
|
||||||
|
gpio_set_level(ROBO_BRC_PIN, 1);
|
||||||
|
Serial.printf("[BRC] Pulse #%lu: released high\n", static_cast<unsigned long>(pulseCount));
|
||||||
|
pulseCount++;
|
||||||
|
|
||||||
// vTaskDelayUntil keeps a steady period even if the loop body jitters.
|
vTaskDelayUntil(&nextWake, BRC_PERIOD);
|
||||||
vTaskDelayUntil(&nextWake, delay);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void roombaTask(void * /*parameter*/) {
|
||||||
|
// Give the Roomba a moment after wake-up before issuing commands.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|
||||||
|
Serial.println("Sending Start (128)...");
|
||||||
|
sendRoombaCommand({128}); // Start OI -> Passive mode.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
Serial.println("Switching to Safe mode (131)...");
|
||||||
|
sendRoombaCommand({131}); // Safe gives actuator control with failsafes.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
Serial.println("Loading a short test song into slot 0 (Song, opcode 140)...");
|
||||||
|
// Song format: [140][song #][length][note][duration]...
|
||||||
|
// Duration units are 1/64ths of a second; 32 ≈ 0.5 s.
|
||||||
|
sendRoombaCommand({140, 0, 1, 69, 32}); // A4 for ~0.5 s.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
Serial.println("Playing song 0 (Play, opcode 141)...");
|
||||||
|
sendRoombaCommand({141, 0});
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1500)); // Allow song to finish.
|
||||||
|
|
||||||
|
Serial.println("Initial song played. Roomba ready for bumper test.");
|
||||||
|
|
||||||
|
// Nothing else to do on this task; park it.
|
||||||
|
vTaskDelete(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sensorTask(void * /*parameter*/) {
|
||||||
|
constexpr TickType_t pollPeriod = pdMS_TO_TICKS(100); // ~10 Hz polling.
|
||||||
|
TickType_t nextWake = xTaskGetTickCount();
|
||||||
|
bool bumperActive = false;
|
||||||
|
|
||||||
|
// Allow initialization commands to finish before polling.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Request packet 7 (Bumps & Wheel Drops).
|
||||||
|
sendRoombaCommand({142, 7});
|
||||||
|
|
||||||
|
uint8_t packet = 0;
|
||||||
|
const size_t received = Serial1.readBytes(&packet, 1);
|
||||||
|
if (received == 1) {
|
||||||
|
Serial.printf("[Sensor] Packet 7 raw byte: 0x%02X\n", packet);
|
||||||
|
const bool bumpRight = packet & 0b00000001;
|
||||||
|
const bool bumpLeft = packet & 0b00000010;
|
||||||
|
const bool wheelDropRight = packet & 0b00000100;
|
||||||
|
const bool wheelDropLeft = packet & 0b00001000;
|
||||||
|
const bool frontBump = bumpLeft || bumpRight;
|
||||||
|
|
||||||
|
if (wheelDropLeft || wheelDropRight) {
|
||||||
|
Serial.printf("[Sensor] Wheel drop detected (L:%d R:%d)\n",
|
||||||
|
wheelDropLeft, wheelDropRight);
|
||||||
|
}
|
||||||
|
if (frontBump && !bumperActive) {
|
||||||
|
Serial.println("Front bumper hit! Playing song 0.");
|
||||||
|
sendRoombaCommand({141, 0});
|
||||||
|
}
|
||||||
|
if (!frontBump && bumperActive) {
|
||||||
|
Serial.println("Front bumper released.");
|
||||||
|
}
|
||||||
|
bumperActive = frontBump;
|
||||||
|
} else {
|
||||||
|
Serial.println("[Sensor] Timed out waiting for packet 7.");
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelayUntil(&nextWake, pollPeriod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
while (!Serial && millis() < 3000) {
|
while (!Serial && millis() < 2000) {
|
||||||
// Give USB CDC boards a moment to enumerate; safe to ignore for pure UART boards.
|
|
||||||
delay(10);
|
delay(10);
|
||||||
}
|
}
|
||||||
Serial.println("FreeRTOS dual LED blink demo starting up...");
|
Serial.println("\nRoomba hardware smoke test starting...");
|
||||||
|
|
||||||
// The Arduino core already starts the scheduler after setup() returns.
|
// Configure the BRC pin; keep it high (inactive) until the pulse task starts.
|
||||||
xTaskCreate(
|
pinMode(static_cast<uint8_t>(ROBO_BRC_PIN), OUTPUT);
|
||||||
ledTask, // Task function.
|
gpio_set_level(ROBO_BRC_PIN, 1);
|
||||||
"LED1", // Label (shows up in diagnostics).
|
|
||||||
2048, // Stack size in words.
|
|
||||||
reinterpret_cast<void *>(static_cast<intptr_t>(LED1_PIN)),
|
|
||||||
1, // Priority.
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
xTaskCreate(
|
// Initialize UART1 for the Roomba Open Interface at its default baud (115200 8N1).
|
||||||
ledTask,
|
Serial1.begin(115200, SERIAL_8N1, ROBO_UART_RX, ROBO_UART_TX);
|
||||||
"LED2",
|
Serial1.setTimeout(150); // Enough headroom for sensor replies.
|
||||||
2048,
|
Serial.println("UART1 configured for Roomba at 115200 8N1.");
|
||||||
reinterpret_cast<void *>(static_cast<intptr_t>(LED2_PIN)),
|
|
||||||
1,
|
// Launch the tasks that drive the Roomba and keep it awake.
|
||||||
nullptr);
|
xTaskCreatePinnedToCore(brcTask, "BrcPulse", 2048, nullptr, 1, nullptr, APP_CPU_NUM);
|
||||||
|
xTaskCreatePinnedToCore(roombaTask, "RoombaInit", 4096, nullptr, 1, nullptr, APP_CPU_NUM);
|
||||||
|
xTaskCreatePinnedToCore(sensorTask, "SensorPoll", 4096, nullptr, 1, nullptr, APP_CPU_NUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// Leave loop() empty; the FreeRTOS tasks do the work.
|
// Nothing needed here; FreeRTOS tasks run everything.
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user