From 84ddd7e40ed482d459db05a7b4409087870978fc Mon Sep 17 00:00:00 2001 From: legop3 Date: Wed, 5 Nov 2025 17:31:25 -0500 Subject: [PATCH] hardware test complete --- README.md | 2 +- notes.md | 8 +-- platformio.ini | 4 +- src/main.cpp | 144 ++++++++++++++++++++++++++++++++++++------------- 4 files changed, 116 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 5189c59b..c00f7efd 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ on each roomba: - USB wifi card - microphone - speaker -- MAYBE a master relay which can be turned off programatically to save the roomba from discharging \ No newline at end of file +- MAYBE a master relay which can be turned off programatically to save the roomba from discharging. based on battery voltage plus urgent battery #? \ No newline at end of file diff --git a/notes.md b/notes.md index 1d435dbe..5ca73285 100644 --- a/notes.md +++ b/notes.md @@ -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 +one single system for loading and saving user settings + ## esp-server comms @@ -19,6 +21,6 @@ rover's name enable / disable for each motor camera IP address battery info (for different battery behaviors): - full number - warn number - urgent number \ No newline at end of file +- full number +- warn number +- urgent number \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 17ce3a24..41fa1ccd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,6 +1,6 @@ -[env:esp32dev] +[env:esp32s3] platform = espressif32 -board = esp32dev +board = esp32-s3-devkitc-1 framework = arduino monitor_speed = 115200 diff --git a/src/main.cpp b/src/main.cpp index 0ca6584c..39362413 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,59 +1,131 @@ #include -// Use two GPIOs with onboard-friendly defaults; adjust to match your dev kit. -constexpr gpio_num_t LED1_PIN = GPIO_NUM_2; // Often labeled "LED_BUILTIN". -constexpr gpio_num_t LED2_PIN = GPIO_NUM_4; +// --- Hardware mapping ------------------------------------------------------- +// Adjust these pins to match how your level shifter connects the ESP32 to the Roomba. +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. -constexpr TickType_t LED2_DELAY = pdMS_TO_TICKS(700); // ~1.4 Hz blink. +// FreeRTOS cadences (1 Hz pulse, 150 ms low to ensure Roomba notices). +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. -void ledTask(void *parameter) { - const gpio_num_t pin = static_cast(reinterpret_cast(parameter)); - const TickType_t delay = (pin == LED1_PIN) ? LED1_DELAY : LED2_DELAY; +// Simple helper to send an Open Interface command over UART. +void sendRoombaCommand(std::initializer_list bytes) { + Serial1.write(bytes.begin(), bytes.size()); + Serial1.flush(); // Ensure command clears the UART FIFO before proceeding. +} - pinMode(pin, OUTPUT); - - // Align the first toggle with system tick so the cadence stays consistent. +void brcTask(void * /*parameter*/) { TickType_t nextWake = xTaskGetTickCount(); + uint32_t pulseCount = 0; - bool state = false; while (true) { - digitalWrite(pin, state ? HIGH : LOW); - state = !state; + // Idle high, pulse low to reset the five-minute sleep timer. + Serial.printf("[BRC] Pulse #%lu: pulling low\n", static_cast(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(pulseCount)); + pulseCount++; - // vTaskDelayUntil keeps a steady period even if the loop body jitters. - vTaskDelayUntil(&nextWake, delay); + vTaskDelayUntil(&nextWake, BRC_PERIOD); + } +} + +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() { Serial.begin(115200); - while (!Serial && millis() < 3000) { - // Give USB CDC boards a moment to enumerate; safe to ignore for pure UART boards. + while (!Serial && millis() < 2000) { 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. - xTaskCreate( - ledTask, // Task function. - "LED1", // Label (shows up in diagnostics). - 2048, // Stack size in words. - reinterpret_cast(static_cast(LED1_PIN)), - 1, // Priority. - nullptr); + // Configure the BRC pin; keep it high (inactive) until the pulse task starts. + pinMode(static_cast(ROBO_BRC_PIN), OUTPUT); + gpio_set_level(ROBO_BRC_PIN, 1); - xTaskCreate( - ledTask, - "LED2", - 2048, - reinterpret_cast(static_cast(LED2_PIN)), - 1, - nullptr); + // Initialize UART1 for the Roomba Open Interface at its default baud (115200 8N1). + Serial1.begin(115200, SERIAL_8N1, ROBO_UART_RX, ROBO_UART_TX); + Serial1.setTimeout(150); // Enough headroom for sensor replies. + Serial.println("UART1 configured for Roomba at 115200 8N1."); + + // Launch the tasks that drive the Roomba and keep it awake. + 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() { - // Leave loop() empty; the FreeRTOS tasks do the work. + // Nothing needed here; FreeRTOS tasks run everything. vTaskDelay(pdMS_TO_TICKS(1000)); }