diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/index.md b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/index.md index 2031954080b..2f557da5263 100644 --- a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/index.md +++ b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/index.md @@ -10,62 +10,74 @@ Autonomous Robot with Mapping and Simplified SLAM ## Description -AutoNav is an autonomous mobile robot that explores an unknown space, builds a 2D obstacle map in real time, and makes navigation decisions independently — without human intervention. The project implements a simplified SLAM (Simultaneous Localization and Mapping) system, adapted to the hardware constraints of an STM32 microcontroller. +AutoNav is an autonomous mobile robot that explores an unknown space, builds a 2D obstacle map in real time, and makes navigation decisions independently, without human intervention. The project implements a simplified SLAM (Simultaneous Localization and Mapping) system, adapted to the hardware constraints of an STM32 microcontroller. -The robot uses three ultrasonic sensors and a scanning servo to detect surrounding obstacles, wheel encoders for odometry, and an IMU for heading error correction. From this data, it builds a probabilistic occupancy grid — a 2D map where each cell has an associated probability of containing an obstacle. +The robot uses a ultrasonic sensor and a scanning servo to detect surrounding obstacles, wheel encoders for odometry, and an IMU for heading error correction. From this data, it builds a probabilistic occupancy grid, a 2D map where each cell has an associated probability of containing an obstacle. -The map is displayed live on a color LCD mounted on the robot, updated at 10Hz. Simultaneously, data is transmitted wirelessly via ESP8266 to a PC, where it can be visualized in real time through a graphical interface. - -The exploration algorithm uses frontier-based exploration: the robot identifies boundaries between explored and unknown space and autonomously heads toward the nearest unexplored frontier until the accessible space is completely mapped. +The map is displayed live on a color LCD mounted on the robot, updated at 1.3 Hz. ## Motivation -This project was chosen because it covers all peripherals and protocols studied in the lab — SPI, I2C, UART, PWM, GPIO, ADC, TIM input capture — demonstrated simultaneously in a functional integrated system. It implements algorithms relevant to real-world applications: odometry, sensor fusion, probabilistic mapping, and graph search for trajectory planning — all in Rust without an operating system. Similar SLAM systems are used in industrial robots (Amazon warehouses), autonomous vacuum cleaners (Roomba), exploration drones, and autonomous vehicles. +This project was chosen because it covers all peripherals and protocols studied in the lab (SPI, I2C, PWM, GPIO, ADC, TIM input capture) demonstrated simultaneously in a functional integrated system. It implements algorithms relevant to real-world applications: odometry, sensor fusion, probabilistic mapping — all in Rust without an operating system. Similar SLAM systems are used in industrial robots (Amazon warehouses), autonomous vacuum cleaners (Roomba), exploration drones, and autonomous vehicles. ## Architecture -The system is structured in four functional layers: +**1. MCU (STM32 Nucleo-U545RE-Q)** +The central unit running all Embassy-rs async tasks. ` +Coordinates all subsystems and shared state variables (Pose, Occupancy Grid, and Visited Cells Matrix), avoiding data races and enforcing correctness by using asynchronous Mutexes (`ThreadModeRawMutex`). -- **Perception Layer**: 3x HC-SR04 + scanning servo + MPU-6050 IMU + wheel encoders — collects data about the environment and robot movement -- **Localization Layer**: odometry from encoders, fused with the IMU gyroscope through a complementary filter — estimates the robot's position and orientation in space -- **Mapping Layer**: 32x32 occupancy grid updated through Bresenham ray casting — builds the probabilistic obstacle map -- **Planning Layer**: frontier-based exploration + PID on heading — decides the next destination and controls movement +**2. Motor Subsystem** +The L298N dual H-bridge receives 1 kHz PWM signals from TIM3 (CH1 on PC6, CH2 on PC7) and drives two DC motors (left/right). Direction is controlled via four GPIO output pins (PA1, PA4, PB0, PC1 — the IN1–IN4 lines of the L298N). Two Hall encoder discs are read via GPIO EXTI interrupts (PB14 for left, PB15 for right): each rising or falling edge increments or decrements a signed tick counter in `RobotState`, with sign determined by the current commanded motor direction. + +**3. Sensing Subsystem** +- **HC-SR04 ultrasonic sensor** (GPIO trigger on PB4, EXTI echo on PB10): distance is measured by busy-polling the echo line (no `async` awaits inside the timing loops, guaranteeing both edges are captured without executor preemption; I of course first tried to make this task run async using .wait_for_* functions wherever I could, but this resulted in low responsiveness and delayed robot reaction). The sensor is swept by an SG90 servo to three positions (far-left ≈ 0.105, center ≈ 0.075, far-right ≈ 0.045 duty cycle on TIM2 CH4, PA3 at 50 Hz) to collect left, center, and right scan distances. +- **MPU-6050 IMU** (I2C1 on PB6/PB7, address `0x68`): supplies raw gyroscope Z-axis data at ±250°/s full-scale. On startup, 100 samples are averaged to compute and store a static gyro bias before navigation begins. -![Block Scheme](schema_bloc.svg) +**4. Localization Subsystem** +Pose estimation combines two independent angle sources through a complementary filter (\alpha = 0.98 gyro, 0.02 odometry): + +- `imu_task` integrates bias-corrected (motors are asymmetrical, unfortunately and calibration had to be done) gyro Z at ~100 Hz to maintain `gyro_theta`, zeroing out readings below a 0.005 rad/s deadband to suppress drift at rest. +- `odometry_task` derives `theta_odom` from differential encoder ticks every 20 ms using the wheel geometry (radius = 3.4 cm, base = 13.5 cm, 38 ticks/rev). Position `(x, y)` is then integrated from the heading `theta`. -### Processing Pipeline +**5. Mapping & Navigation Subsystem** +- `mapping_task` consumes fresh scan readings published by `nav_task` into `STATE` (up to 3 readings per scan cycle: center, left, right). For each fresh reading it calls `integrate_scan`, which uses `ray_cast` (Bresenham's line algorithm) to mark all cells along the ray as free (decrement by 3, floored at 0) and the endpoint cell as occupied (increment by 20, capped at 255) in the 32×32 `GRID`. Each cell starts at `UNKNOWN = 128`; cells below 100 are considered free, above 155 occupied. +- `visit_marker_task` increments the `VISITED` counter for the robot's current grid cell at ~3 Hz, building a heatmap of explored areas. +- `nav_task` implements reactive obstacle avoidance with visit-aware turn selection: it drives forward with a PID heading-hold loop (Kp = 0.4, Ki = 0.0, Kd = 0.05, real-time dt measurement), stops on obstacle detection at 18 cm, applies a 120 ms active brake pulse, scans left and right with the servo, then picks the clearer direction, breaking ties by comparing 3×3 neighborhood visit counts from `VISITED` to prefer less-explored areas. -At each 100ms cycle, the system executes sequentially: +**6. Display Subsystem** +`display_task` drives an ST7735S 128×160 color LCD over SPI1 at 4 MHz (SCK PA5, MOSI PA7, CS PB5, DC PB3, RST PC2). The top 128×128 px renders the 32×32 occupancy grid at 4×4 px per cell. A dirty-tracking mechanism repaints only cells whose color index changed since the last frame, reducing SPI traffic. The robot is overlaid as a yellow triangle with a green heading line. A status bar at the bottom changes color to reflect the current navigation state. The display refreshes at ~1.3 Hz (750 ms sleep per frame), fast enough to observe map growth, slow enough to leave CPU budget for sensor tasks. -1. Read encoders -> calculate distance traveled per wheel -2. Read IMU gyroscope -> heading correction through complementary filter -3. Update odometry -> current position (x, y, theta) in space -4. Servo scan 5 positions -> 5 ultrasonic distances -> 5 obstacle points in space -5. Update occupancy grid -> ray casting for free cells + obstacle probability increment -6. Frontier detection -> find nearest unexplored cell adjacent to free space -7. PID heading -> direction correction calculation -> motor PWM -8. LCD render -> updated 2D map + robot position + status -9. UART ESP8266 -> compressed grid wireless transmission +![Block Scheme](schema_bloc_hardware.svg) ## Log - - - + ### Week 5 - 11 May - -Decided upon hardware components and designed a block scheme with the hardware architecture I will built. - + +Decided upon hardware components and designed a block scheme with the hardware architecture I will build. Settled on a reactive SLAM approach (no global path planner) with a 32×32 probabilistic occupancy grid updated by Bresenham ray casting and a complementary filter for heading fusion. + ### Week 12 - 18 May - -Asembled hardware components, tested each component (to verify its functionality) through simple tasks and finalized hardware implementation. - + +Assembled hardware components. Tested each component individually: verified HC-SR04 ultrasonic echo timing, SG90 servo sweep range, MPU-6050 gyro output over I2C, Hall encoder edge counting on EXTI interrupts, and ST7735S display init over SPI. Finalized wiring and hardware integration. + ### Week 19 - 25 May - + +Implemented and integrated the full software stack. Key challenges resolved during this week: + +**Ultrasonic timing**: The initial async implementation using `wait_for_rising_edge` / `wait_for_falling_edge` from `ExtiInput` produced frequent fall-timeout errors. The Embassy executor was yielding between arming the rising-edge wait and the falling-edge wait, allowing other tasks to run and causing the echo's falling edge to be missed entirely. Replaced with a busy-poll approach — tight loops on `echo.is_high()` with no `.await` — which blocks the executor for the duration of the pulse (~1 ms typical, 25 ms max) and reliably captures both edges. + +**PID heading hold**: The first version used a hard-coded `dt = 5 ms` matching the `FORWARD_LOOP_MS` constant. In practice the loop period is dominated by `get_dist` execution (~70–90 ms per call), causing the derivative term to be scaled by ~14×, making the robot snake aggressively. Fixed by measuring real elapsed time with `Instant::now()` each iteration and clamping dt to [20 ms, 200 ms]. + +**Obstacle threshold tuning**: Initial threshold of 15 cm gave insufficient braking distance — motors coast after speed = 0, and the scan-and-turn sequence adds >1.3 s of forward drift. Tried 22 cm, which caused the robot to get stuck rotating in any corridor where an occasional reading fell in the 15–22 cm band. Settled on 18 cm combined with an active 120 ms brake pulse (reverse at 0.30 speed) applied immediately on obstacle detection. + +**Visit-aware exploration**: Without a turn bias, the robot would repeatedly re-enter already-explored corridors. Implemented `visit_marker_task` (3 Hz cell counter) and `visit_score_in_direction` (3×3 neighborhood sum), used by `nav_task` to break clearance ties in favor of less-visited directions. + ## Hardware + +The robot is built on a 2WD chassis powered by two DC motors with Hall encoders, driven by an L298N dual H-bridge. A single HC-SR04 ultrasonic sensor mounted on an SG90 scanning servo provides obstacle detection in three directions (front, left, right) without requiring multiple sensors. An MPU-6050 IMU provides gyroscope data for heading correction. An ST7735S 128×160 color LCD displays the live occupancy grid map, robot pose, and navigation state. The system is powered by a 7.4V 2000mAh LiPo battery with an LM2596 voltage regulator stepping down to 5V for logic. + +![Hardware](masina-slam.webp) -The robot is built on a 2WD chassis with two DC motors with Hall encoders for precise odometry. Three HC-SR04 ultrasonic sensors (front, left, right) mounted on an SG90 scanning servo provide obstacle detection. An MPU-6050 IMU handles heading correction, while two IR sensors detect floor edges. An ST7735 128x160 color LCD displays the live map, and an ESP8266 WiFi module streams data wirelessly to a PC. The system is powered by a 7.4V 2000mAh LiPo battery with an LM2596 voltage regulator. - -![Hardware](masina_slam.webp) +![Video](https://drive.google.com/file/d/1XOovrqZ5_l_vMKnRxfIBl36JoMaDF0Ii/view?usp=sharing) ### Schematics @@ -84,16 +96,63 @@ The robot is built on a 2WD chassis with two DC motors with Hall encoders for pr | [MPU-6050 IMU](https://www.optimusdigital.ro/en/inertial-sensors/96-mpu-6050-imu.html) | Gyroscope heading + accelerometer | [15 RON](https://www.optimusdigital.ro/en/inertial-sensors/96-mpu-6050-imu.html) | | [IR Sensors x2](https://www.optimusdigital.ro/en/optical-sensors/4-ir-obstacle-sensor.html) | Floor edge / table edge detection | [10 RON](https://www.optimusdigital.ro/en/optical-sensors/4-ir-obstacle-sensor.html) | | [ST7735 LCD 128x160](https://www.optimusdigital.ro/en/lcds/3-18-inch-tft-lcd.html) | Live 2D map + robot status display | [20 RON](https://www.optimusdigital.ro/en/lcds/3-18-inch-tft-lcd.html) | -| [ESP8266 WiFi Module](https://www.optimusdigital.ro/en/wireless-modules/28-esp8266-wifi-module.html) | Wireless map streaming to PC | [20 RON](https://www.optimusdigital.ro/en/wireless-modules/28-esp8266-wifi-module.html) | -| RGB LEDs x4 | Visual robot state status | 8 RON | -| Passive Buzzer | Audio feedback for events | 5 RON | | LiPo Battery 7.4V 2000mAh | Autonomous power supply (~45min) | 35 RON | -| LM2596 5V Regulator | Voltage step-down for logic | 10 RON | -| Capacitors 100uF x4 | Motor noise filtering | 5 RON | | Breadboard + Jumper Wires | Prototype circuit | 30 RON | -| Resistors + Misc | Protection + connections | 8 RON | ## Software + +The entire program is `#![no_std]` and `#![no_main]` (no heap, no operating system, no RTOS scheduler). All concurrency is cooperative and driven by `async`/`await` under the Embassy executor. + +### Concurrency Model + +Embassy runs a single-threaded cooperative executor. Every task is a Rust `async fn` marked with `#[embassy_executor::task]`. Because only one task runs at a time and tasks yield at every `.await` point, shared state is safely exchanged through three `Mutex` globals: `STATE` (the main `RobotState` struct), `GRID` (the 32x32 occupancy grid), and `VISITED` (the visit heatmap). Mutex guards are held for the minimum duration possible, tasks snapshot the fields they need and drop the guard immediately - to avoid blocking time-sensitive tasks such as `encoder_*_task`. + +One deliberate exception to async discipline is the echo measurement in `get_dist`: the timing loops are busy-polls with no `.await`, blocking the executor for up to ~25 ms. This is intentional, since yielding between arming the rising-edge wait and the falling-edge wait caused the executor to miss the echo's falling edge entirely (fall-timeout errors). The busy-poll trades a short CPU window for measurement correctness. + +### Embassy-rs Async Tasks + +| Task | Frequency | Responsibility | +|------|-----------|----------------| +| `encoder_left_task` / `encoder_right_task` | Interrupt-driven (EXTI) | Waits for any edge on encoder pins PB14/PB15; increments or decrements `left_ticks` / `right_ticks` in `STATE` based on the current commanded motor direction. | +| `imu_task` | ~100 Hz | Initializes MPU-6050 over I2C, calibrates gyro bias from 100 startup samples, then continuously reads raw gyro Z, integrates to `gyro_theta` (with 0.005 rad/s deadband), applies complementary filter with `theta_odom`, and writes fused `theta` to `STATE`. Sets `gyro_calibrated = true` once done, unblocking `nav_task`. | +| `odometry_task` | 50 Hz (20 ms) | Drains and resets `left_ticks` / `right_ticks` from `STATE`, computes per-wheel arc length (wheel radius 3.4 cm, 38 ticks/rev), updates `theta_odom` and integrates `(x, y)` from the derived `theta`. Clamps position to [0, 160) cm. | +| `mapping_task` | 20 Hz (50 ms) | Reads and clears `last_scan_fresh[3]` from `STATE`. For each fresh slot, converts the sensor-relative angle to world frame using `theta`, then calls `integrate_scan` -> `ray_cast` to update `GRID`. | +| `visit_marker_task` | ~3 Hz (300 ms) | Reads `(x, y)` from `STATE`, converts to grid coordinates, and saturating-increments the corresponding cell in `VISITED`. | +| `nav_task` | ~10-15 Hz (sensor-paced) | Waits for `gyro_calibrated && display_initialized`. Then loops: measures front distance with PID heading hold (Kp=0.4, Ki=0.0, Kd=0.05, real-time dt); on obstacle, applies brake pulse, sweeps servo left/right, picks turn direction by clearance and visit score, executes timed in-place rotation. Publishes all scan readings to `STATE.last_scan_*`. | +| `motor_task` | 50 Hz (20 ms) | Reads `motor_left_speed` / `motor_right_speed` from `STATE` and drives L298N PWM duty cycle and direction pins. | +| `display_task` | ~1.3 Hz (750 ms) | Snapshots `GRID`, `VISITED`, and pose from `STATE`. Dirty-repaints only changed cells on the ST7735S (4x4 px per cell, 128x128 px grid area). Overlays robot as a yellow triangle with green heading line. Updates a color-coded nav-state status bar. Sets `display_initialized = true` after init, unblocking `nav_task`. | +| `log_task` | 2 Hz (500 ms) | Emits pose `(x, y, theta)`, raw gyro, scan distances, motor speeds, nav state, and ultrasonic diagnostic counters (ok / out-of-range / rise-timeout / fall-timeout) over RTT via `defmt`. | + +### Global Shared State + +**`RobotState` struct — protected by `Mutex`:** + +| Field | Type | Writer | Readers | Meaning | +|-------|------|--------|---------|---------| +| `x`, `y` | `f32` | `odometry_task` | `mapping_task`, `nav_task`, `visit_marker_task`, `display_task` | Robot world position (cm) | +| `theta` | `f32` | `imu_task` | `odometry_task`, `nav_task`, `mapping_task`, `display_task` | Derived heading (rad) from complementary filter | +| `theta_odom` | `f32` | `odometry_task` | `imu_task` | Pure encoder-derived heading, fed into complementary filter | +| `gyro_bias` | `f32` | `imu_task` (startup) | `imu_task` | Static gyro Z offset (rad/s) | +| `gyro_calibrated` | `bool` | `imu_task` | `nav_task` | Startup gate: nav waits until IMU calibration completes | +| `display_initialized` | `bool` | `display_task` | `nav_task` | Startup gate: nav waits until display init finishes | +| `last_gyro_raw`, `last_omega` | `i16`, `f32` | `imu_task` | `log_task` | Latest raw gyro reading and deadband-filtered angular velocity | +| `left_ticks`, `right_ticks` | `i32` | `encoder_left/right_task` | `odometry_task` (drains to 0) | Signed encoder edge counts since last odometry cycle | +| `last_scan_dist[3]` | `[f32; 3]` | `nav_task` | `mapping_task`, `log_task` | Ultrasonic distances for center [0], left [1], right [2] (cm) | +| `last_scan_angle[3]` | `[f32; 3]` | `nav_task` | `mapping_task` | Sensor-relative ray angles: 0.0, +pi/2, -pi/2 | +| `last_scan_fresh[3]` | `[bool; 3]` | `nav_task` (sets) | `mapping_task` (reads and clears) | Indicates which scan slots hold unprocessed readings | +| `motor_left_speed`, `motor_right_speed` | `f32` | `nav_task` | `motor_task`, `encoder_left/right_task` | Commanded speeds in [-1.0, 1.0]; sign encodes direction | +| `nav_state` | `u8` | `nav_task` | `display_task`, `log_task` | FORWARD(0) / STOPPED(1) / SCAN_LEFT(2) / SCAN_RIGHT(3) / TURN_LEFT(4) / TURN_RIGHT(5) / TURN_AROUND(6) | +| `i2c_errors` | `u32` | `imu_task` | `log_task` | Cumulative I2C read failure count | + +**Grid globals:** + +| Static | Type | Writer | Readers | Meaning | +|--------|------|--------|---------|---------| +| `GRID` | `Mutex<_, [[u8; 32]; 32]>` | `mapping_task` | `display_task` | Occupancy probabilities; 128 = unknown, \<100 = free, >155 = occupied | +| `VISITED` | `Mutex<_, [[u8; 32]; 32]>` | `visit_marker_task` | `nav_task` (turn decision) | Per-cell visit count; used to prefer unexplored directions | + +![Software](schema_bloc_software.svg) + | Library | Description | Usage | |---------|-------------|-------| diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina-slam.webp b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina-slam.webp new file mode 100644 index 00000000000..577de357b00 Binary files /dev/null and b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina-slam.webp differ diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina_slam.webp b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina_slam.webp deleted file mode 100755 index edacac5ca9a..00000000000 Binary files a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/masina_slam.webp and /dev/null differ diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc.svg b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc.svg deleted file mode 100755 index ab7ba3fee07..00000000000 --- a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc.svg +++ /dev/null @@ -1,4 +0,0 @@ - - -STM Nucleo-U545RE-QHC-SR04 x 3senzoride distantaServo SG90PWMPWMMPU-6050IMU(acc + giro)Encoder Hallx 2Senzor IR x 2I2CGPIOADCDriver L298NLCD ST7735ESP8266 WiFiLaptopBaterie LiPo7.4VStabilizatorLM2596 5VMotor DC x 2PWMSPIUARTUDP Stream \ No newline at end of file diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_hardware.svg b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_hardware.svg new file mode 100644 index 00000000000..596eecff3b6 --- /dev/null +++ b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_hardware.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + STM Nucleo-U545RE-Q + + + + + + HC-SR04 + senzori + de distanta + + + + + + Servo SG90 + + + + + + + + + PWM + + + + + + + + + + + + + + + + + + + + + PWM + + + + + + + + + + + + + + + + + + MPU-6050 + IMU + (acc + giro) + + + + + + Encoder Hall + x 2 + + + + + + Senzor IR x 2 + + + + + + + + + + + + + + + + + + + + + I2C + + + + + + + + + + + + + + + + + + + + + GPIO + + + + + + + + + ADC + + + + + + + + + + + + + + + + + + Driver L298N + + + + + + LCD ST7735 + + + + + + Baterie LiPo + 7.4V + + + + + + Stabilizator + LM2596 5V + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Motor DC x 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PWM + + + SPI + + + diff --git a/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_software.svg b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_software.svg new file mode 100644 index 00000000000..87991d95d3a --- /dev/null +++ b/website/versioned_docs/version-acs_cc/project/2026/anca_stefania.maxim/schema_bloc_software.svg @@ -0,0 +1,4 @@ + + +Hall EncodersEXTI PB14/PB15MPU-6050I2C1 PB6/PB7HC-SR04GPIO PB4/PB10SG90 servoTIM2 CH4 PA3encoder_leftencoder_rightEXTI interruptimu_task~100 Hz nav_taskPID heading hold (Kp=0.4 Kd=0.05)obstacle detect - stop - scan - turn toavailable direction, using VISITED matrixPWMleft / right ticksthetanav_statethetaSTATE - Mutex<RobotState>x, y - robot position (cm)theta - derived angle (rad)theta_odom - pure headingleft_ticks, right_tickslast_scan_dist[3],scan_fresh[3]motor_left/right_speednav_state (0-6)gyro_calibrateddisplay_initializedticksx,y,theta_odomscan_freshx,ymotor speedsodometry_task50 Hzintegreaza x,ymapping_task20 Hzraycast Bresenheimvisit_marker3 Hzincrementeaza celulamotor_task50 Hzcomanda L298Ndisplay_task1.3 Hzgrid+position+nav_stateGRID32x32VISITED32x32log_task2 Hzlog pose, scan,stateL298NTIM3 PWM + GPIOwrite cellsincrement cellPWM + directieposenav_stateread GRIDreads VISITEDdisplay initialized -> robot can startvisit score \ No newline at end of file