Created
October 10, 2025 12:13
-
-
Save Mechazawa/d00340a2adf43ce120286603a85110ff to your computer and use it in GitHub Desktop.
Simple Ai-Thinker-RD-03 driver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Remove this line if you're working inside Arduino studio if you're getting errors | |
| // Including Arduino manually is only needed for PlatformIO | |
| #include <Arduino.h> | |
| #include "RadarSensor.h" | |
| // The pins I use on the C3 mini v1 | |
| #define RADAR_PIN_TX 7 | |
| #define RADAR_PIN_RX 6 | |
| RadarSensor radar; | |
| void printRadarTarget(uint8_t id); | |
| void setup() | |
| { | |
| pinMode(LED_BUILTIN, OUTPUT); | |
| Serial.begin(115200); | |
| digitalWrite(LED_BUILTIN, HIGH); | |
| radar.begin(RADAR_PIN_RX, RADAR_PIN_TX, 256000); | |
| digitalWrite(LED_BUILTIN, LOW); | |
| delay(10); | |
| } | |
| void loop() | |
| { | |
| // Receive new state from the radar | |
| radar.update(); | |
| // Print the state | |
| printRadarTarget(0); | |
| printRadarTarget(1); | |
| printRadarTarget(2); | |
| } | |
| void printRadarTarget(const uint8_t id) | |
| { | |
| const RadarTarget tgt = radar.getTarget(id); | |
| Serial.print(millis() / 1000.0); | |
| Serial.print('\t'); | |
| Serial.print('R'); | |
| Serial.print(id); | |
| Serial.print('\t'); | |
| if (!tgt.detected) { | |
| Serial.println("?"); | |
| return; | |
| } | |
| Serial.print("A"); | |
| Serial.print(tgt.angle); | |
| Serial.print('\t'); | |
| Serial.print("D"); | |
| Serial.print(static_cast<int>(tgt.distance)); | |
| Serial.print('\t'); | |
| Serial.print("S"); | |
| Serial.print(static_cast<int>(tgt.speed)); | |
| Serial.println("\t"); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "RadarSensor.h" | |
| // https://github.com/Gjorgjevikj/Ai-Thinker-RD-03/blob/main/src/Ai-Thinker-RD-03.h | |
| uint8_t Single_Target_Detection_CMD[12] = {0xFD, 0xFC, 0xFB, 0xFA, 0x02, 0x00, 0x80, 0x00, 0x04, 0x03, 0x02, 0x01}; | |
| uint8_t Multi_Target_Detection_CMD[12] = {0xFD, 0xFC, 0xFB, 0xFA, 0x02, 0x00, 0x90, 0x00, 0x04, 0x03, 0x02, 0x01}; | |
| void RadarSensor::begin(uint8_t rxPin, uint8_t txPin, unsigned long baud) { | |
| Serial1.begin(baud, SERIAL_8N1, rxPin, txPin); | |
| Serial1.setRxBufferSize(RADAR_BUFFER_SIZE); | |
| Serial1.write(Multi_Target_Detection_CMD, sizeof(Multi_Target_Detection_CMD)); | |
| } | |
| bool RadarSensor::update() { | |
| bool ret = false; | |
| static uint8_t buffer[RADAR_BUFFER_SIZE]; | |
| static size_t index = 0; | |
| static enum {WAIT_AA, WAIT_FF, WAIT_03, WAIT_00, RECEIVE_FRAME} state = WAIT_AA; | |
| while (Serial1.available()) { | |
| byte byteIn = Serial1.read(); | |
| switch(state) { | |
| case WAIT_AA: | |
| if(byteIn == 0xAA) state = WAIT_FF; | |
| break; | |
| case WAIT_FF: | |
| if(byteIn == 0xFF) state = WAIT_03; | |
| else state = WAIT_AA; | |
| break; | |
| case WAIT_03: | |
| if(byteIn == 0x03) state = WAIT_00; | |
| else state = WAIT_AA; | |
| break; | |
| case WAIT_00: | |
| if(byteIn == 0x00) { | |
| index = 0; | |
| state = RECEIVE_FRAME; | |
| } else state = WAIT_AA; | |
| break; | |
| case RECEIVE_FRAME: | |
| buffer[index++] = byteIn; | |
| if(index >= 26) { // 24 bytes data + 2 tail bytes | |
| if(buffer[24] == 0x55 && buffer[25] == 0xCC) { | |
| memcpy(_buffer, buffer, RADAR_BUFFER_SIZE); | |
| ret = true; | |
| } | |
| state = WAIT_AA; | |
| index = 0; | |
| } | |
| break; | |
| } | |
| } | |
| return ret; | |
| } | |
| RadarTarget RadarSensor::getTarget(const uint8_t id) { | |
| uint8_t* buf = _buffer + (id * 8); | |
| RadarTarget target; | |
| // Only parse first 8 bytes for the first target | |
| int16_t raw_x = buf[0] | (buf[1] << 8); | |
| int16_t raw_y = buf[2] | (buf[3] << 8); | |
| int16_t raw_speed = buf[4] | (buf[5] << 8); | |
| uint16_t raw_pixel_dist = buf[6] | (buf[7] << 8); | |
| target.detected = !(raw_x == 0 && raw_y == 0 && raw_speed == 0 && raw_pixel_dist == 0); | |
| // correctly parse signed valuss | |
| target.x = ((raw_x & 0x8000) ? 1 : -1) * (raw_x & 0x7FFF); | |
| target.y = ((raw_y & 0x8000) ? 1 : -1) * (raw_y & 0x7FFF); | |
| target.speed = ((raw_speed & 0x8000) ? 1 : -1) * (raw_speed & 0x7FFF); | |
| if (target.detected) { | |
| target.distance = sqrt(target.x * target.x + target.y * target.y); | |
| // angle calculation (convert radians to degrees, then flip) | |
| float angleRad = atan2(target.y, target.x) - (PI / 2); | |
| float angleDeg = angleRad * (180.0 / PI); | |
| target.angle = -angleDeg; // align angle with x measurement positive / negative sign | |
| } else { | |
| target.distance = 0.0; | |
| target.angle = 0.0; | |
| } | |
| return target; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| // Remove this line if you're working inside Arduino studio if you're getting errors | |
| // Including Arduino manually is only needed for PlatformIO | |
| #include <Arduino.h> | |
| #define RADAR_BUFFER_SIZE 64 | |
| typedef struct RadarTarget { | |
| float distance; // mm | |
| float angle; // radians | |
| float speed; // cm/s | |
| int16_t x; // mm | |
| int16_t y; // mm | |
| bool detected; | |
| } RadarTarget; | |
| class RadarSensor { | |
| public: | |
| void begin(uint8_t rxPin, uint8_t txPin, unsigned long baud = 256000); | |
| bool update(); | |
| RadarTarget getTarget(uint8_t id = 0); // No index, only first target | |
| private: | |
| uint8_t _buffer[RADAR_BUFFER_SIZE] = {0}; | |
| }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment