🌐 Level 6 – Wi-Fi Robotics

Project 6.6: "Intelligent Obstacle Avoider"

 

What you’ll learn

  • ✅ Multi‑sensor detection: Read ultrasonic distance and three IR obstacle sensors together for reliable awareness.
  • ✅ Simple mapping: Build a tiny, grid‑like memory of “free” vs “blocked” zones while moving.
  • ✅ Decisions to avoid: Pick safe turns or stops using clear priority rules (STOP → TURN → GO).
  • ✅ Unfamiliar navigation: Probe ahead, sidestep, and keep heading with a minimal explore loop.
  • ✅ Route optimization: Reduce loops with visited marks and a “prefer new paths” rule.

Blocks glossary (used in this project)

  • Digital input (IR): Three infrared obstacle sensors return 1 (blocked) / 0 (clear).
  • Ultrasonic trig/echo: Measure distance in cm with precise microsecond timing.
  • Digital outputs (motor driver): L298N pins for forward, back, left, right, stop.
  • State variables: store headings, visited cells, and last decision.
  • Serial println: Short “SENS:…”, “MAP:…”, “DECIDE:…”, “NAV:…” lines for visibility.

What you need

PartHow many?Pin connection (suggested)
D1 R32 (ESP32)1USB cable (30 cm)
HC‑SR04 ultrasonic1TRIG → Pin 27, ECHO → Pin 25, VCC, GND
IR obstacle sensors3Left → Pin 32, Center → Pin 33, Right → Pin 35
L298N motor driver + motors1Left IN1→18, IN2→19; Right IN3→5, IN4→23
Power for motors (external)1Shared ground with R32

Notes

  • Keep ultrasonic and IR sensor grounds tied to the R32 ground.
  • Aim IR sensors at equal height; test their logic (some boards invert signals—adjust threshold logic as needed).
  • Ultrasonic echo is 5V on some modules—use a safe level shifter or a module with 3.3V‑safe echo.

Before you start

  • USB cable connected
  • Shared ground verified
  • Serial monitor open and shows:
print("Ready!")  # Confirm serial is working so you can see messages

Microprojects 1–5

Microproject 6.6.1 – Obstacle detection with multiple sensors

Goal: Read three IR sensors and ultrasonic distance; print a unified snapshot.
Blocks used:

  • Digital input: Pins 32, 33, 35 for IR.
  • Trig/echo timing: Measure ultrasonic distance.
  • Serial println: “SENS:IR_L/C/R”, “SENS:ULTRA_CM”.

MicroPython code:

import machine  # Import machine for Pin and timing
import time  # Import time for delays and microsecond timing

# IR sensors as digital inputs
irL = machine.Pin(32, machine.Pin.IN)  # Left IR sensor on Pin 32
irC = machine.Pin(33, machine.Pin.IN)  # Center IR sensor on Pin 33
irR = machine.Pin(35, machine.Pin.IN)  # Right IR sensor on Pin 35
print("IR:READY L=32 C=33 R=35")  # Confirm IR sensor pins

# Ultrasonic HC-SR04 pins
trig = machine.Pin(27, machine.Pin.OUT)  # Trigger pin on 27
echo = machine.Pin(25, machine.Pin.IN)  # Echo pin on 25
print("ULTRA:READY TRIG=27 ECHO=25")  # Confirm ultrasonic pins

def ultra_cm():  # Measure distance in centimeters
    trig.value(0)  # Ensure trigger starts LOW
    time.sleep_us(3)  # Short settle time
    trig.value(1)  # Set trigger HIGH to start pulse
    time.sleep_us(10)  # Keep HIGH for 10 microseconds
    trig.value(0)  # Set trigger LOW to finish pulse
    while echo.value() == 0:  # Wait for echo to go HIGH (pulse start)
        pass  # Busy-wait until pulse starts
    start = time.ticks_us()  # Record start time in microseconds
    while echo.value() == 1:  # Wait while echo stays HIGH (pulse duration)
        pass  # Busy-wait until pulse ends
    end = time.ticks_us()  # Record end time in microseconds
    dur = time.ticks_diff(end, start)  # Compute pulse width in microseconds
    cm = dur // 58  # Convert to centimeters (approx: us/58)
    return cm  # Return integer centimeters

cm = ultra_cm()  # Take one ultrasonic measurement
snap = (irL.value(), irC.value(), irR.value())  # Read IR sensor states
print("SENS:IR_L/C/R", snap)  # Print IR snapshot (1=blocked, 0=clear typical)
print("SENS:ULTRA_CM", cm)  # Print ultrasonic distance in cm

Reflection: One glance shows “who” sees an obstacle and “how far” it is.
Challenge:

  • Easy: Read ultrasonic 3 times and print the average.
  • Harder: Add a timeout guard to ultra_cm so it returns 999 if no echo arrives.

Microproject 6.6.2 – Simple obstacle mapping

Goal: Maintain a tiny rolling map of “front status”: FREE, NEAR, BLOCK.
Blocks used:

  • Thresholds: near_cm and block_cm.
  • List buffer: store last 5 snapshots.

MicroPython code:

near_cm = 30  # Distance threshold for NEAR obstacles
block_cm = 15  # Distance threshold for BLOCK obstacles
map_buf = []  # Buffer to store recent front states
print("MAP:THRESH near", near_cm, "block", block_cm)  # Print mapping thresholds

def classify_front(irC_val, cm):  # Classify front status from center IR and distance
    if (irC_val == 1) or (cm <= block_cm):  # If center sees obstacle or very close
        status = "BLOCK"  # Strong block status
    elif cm <= near_cm:  # If object is near but not blocking
        status = "NEAR"  # Near status
    else:  # Otherwise clear
        status = "FREE"  # Free status
    print("MAP:FRONT", status)  # Print classification
    return status  # Return status

cm = ultra_cm()  # Measure distance once
front = classify_front(irC.value(), cm)  # Classify using center IR and distance
map_buf.append(front)  # Store status in buffer
if len(map_buf) > 5:  # If buffer exceeds 5 entries
    map_buf.pop(0)  # Remove oldest entry
print("MAP:BUF", map_buf)  # Print buffer contents

Reflection: A small buffer smooths decisions—one bad read won’t cause panic.
Challenge:

  • Easy: Print “MAP:STABLE” when last 3 entries match.
  • Harder: Track left/right “SIDE:HIT” if IR_L or IR_R stay 1 for two reads.

Microproject 6.6.3 – Decision‑making to avoid

Goal: Choose STOP, TURN_LEFT, TURN_RIGHT, or GO based on IR and distance.
Blocks used:

  • Priority rule: BLOCK → STOP; side hits → turn; else → go.
  • Serial println: “DECIDE:…”.

MicroPython code:

def decide_action(irL_val, irC_val, irR_val, cm):  # Decide what the robot should do
    if (irC_val == 1) or (cm <= block_cm):  # If front is blocked
        act = "STOP"  # Stop immediately
    elif irL_val == 1 and irR_val == 0:  # If left side blocked and right clear
        act = "TURN_RIGHT"  # Turn right to avoid left obstacle
    elif irR_val == 1 and irL_val == 0:  # If right side blocked and left clear
        act = "TURN_LEFT"  # Turn left to avoid right obstacle
    elif cm <= near_cm:  # If near but not blocked
        act = "SLOW_GO"  # Move slowly forward
    else:  # Otherwise clear
        act = "GO"  # Move forward normally
    print("DECIDE:", act)  # Print decision
    return act  # Return decision

cm = ultra_cm()  # Measure distance
act = decide_action(irL.value(), irC.value(), irR.value(), cm)  # Decide action
print("NEXT:", act)  # Print next action for clarity

Reflection: Simple rules make consistent behavior—students can read and trust each branch.
Challenge:

  • Easy: Add “TURN_LEFT_HARD/RIGHT_HARD” when side+near happen together.
  • Harder: Add a cooldown (200 ms) after STOP to avoid rapid flip‑flop.

Microproject 6.6.4 – Navigating in unfamiliar environments

Goal: Execute decisions with safe motor pulses and probing behavior.
Blocks used:

  • Motor helpers: forward, slow_forward, left, right, stop.
  • Probe move: tiny forward after a turn to test clearance.

MicroPython code:

# Motor pins for L298N driver
L_IN1 = machine.Pin(18, machine.Pin.OUT)  # Left IN1
L_IN2 = machine.Pin(19, machine.Pin.OUT)  # Left IN2
R_IN3 = machine.Pin(5, machine.Pin.OUT)   # Right IN3
R_IN4 = machine.Pin(23, machine.Pin.OUT)  # Right IN4
print("MOTORS:READY 18/19 5/23")  # Confirm motor pins

def motors_stop():  # Stop both motors
    L_IN1.value(0)  # Left IN1 LOW
    L_IN2.value(0)  # Left IN2 LOW
    R_IN3.value(0)  # Right IN3 LOW
    R_IN4.value(0)  # Right IN4 LOW
    print("MOVE:STOP")  # Print stop

def motors_forward(pulse=0.20):  # Move forward for a pulse
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:FWD", pulse)  # Print forward pulse
    time.sleep(pulse)  # Run motors for pulse duration
    motors_stop()  # Stop after pulse

def motors_forward_slow(pulse=0.12):  # Move forward slowly
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:FWD_SLOW", pulse)  # Print slow forward pulse
    time.sleep(pulse)  # Run motors for pulse duration
    motors_stop()  # Stop after pulse

def turn_left(pulse=0.16):  # Turn left in place
    L_IN1.value(0)  # Left backward LOW
    L_IN2.value(1)  # Left backward HIGH
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:LEFT", pulse)  # Print left turn pulse
    time.sleep(pulse)  # Run turn for pulse
    motors_stop()  # Stop after turn

def turn_right(pulse=0.16):  # Turn right in place
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(0)  # Right backward LOW
    R_IN4.value(1)  # Right backward HIGH
    print("MOVE:RIGHT", pulse)  # Print right turn pulse
    time.sleep(pulse)  # Run turn for pulse
    motors_stop()  # Stop after turn

def probe_forward():  # Small probe forward to test space
    print("NAV:PROBE")  # Print probe action
    motors_forward(pulse=0.10)  # Move a tiny forward pulse

act = decide_action(irL.value(), irC.value(), irR.value(), ultra_cm())  # Decide based on sensors
if act == "STOP":  # If blocked
    motors_stop()  # Stop immediately
elif act == "TURN_LEFT":  # If need to turn left
    turn_left(0.18)  # Turn left slightly stronger
    probe_forward()  # Probe forward after turn
elif act == "TURN_RIGHT":  # If need to turn right
    turn_right(0.18)  # Turn right slightly stronger
    probe_forward()  # Probe forward after turn
elif act == "SLOW_GO":  # If near but not blocked
    motors_forward_slow(0.12)  # Move forward slowly
else:  # If clear
    motors_forward(0.20)  # Move forward normally

Reflection: Safe pulses and tiny probes make exploration steady; no wild swings or stalls.
Challenge:

  • Easy: Add a second probe if the first shows NEAR but not BLOCK.
  • Harder: Track last turn direction and alternate to avoid hugging one wall forever.

Microproject 6.6.5 – Route optimization

Goal: Reduce cycles with visited markers and a “prefer new paths” rule.
Blocks used:

  • Visited set: Hash simple coordinates or steps.
  • Preference: Avoid choosing the last 2 recently visited headings.

MicroPython code:

visited = set()  # Create a set to store visited tags
recent = []  # Create a list to store recent decisions
print("ROUTE:INIT")  # Print route system init

def mark(tag):  # Mark a visited tag (e.g., TURN_LEFT at index)
    visited.add(tag)  # Add tag to visited set
    recent.append(tag)  # Append tag to recent list
    if len(recent) > 2:  # If recent list grows beyond 2
        recent.pop(0)  # Remove oldest entry
    print("ROUTE:VISITED", list(visited))  # Print visited list

def prefer_new(options):  # Choose an option not in recent if possible
    for opt in options:  # Iterate possible decisions
        if opt not in recent:  # If option not in recent list
            print("ROUTE:CHOICE", opt)  # Print chosen option
            return opt  # Return this option
    print("ROUTE:CHOICE_FALLBACK", options[0])  # Print fallback choice
    return options[0]  # Fallback to first option

# Example of preference usage
cval = irC.value()  # Read center IR
lval = irL.value()  # Read left IR
rval = irR.value()  # Read right IR
cm = ultra_cm()  # Read ultrasonic distance
act = decide_action(lval, cval, rval, cm)  # Decide original action

if act in ("TURN_LEFT", "TURN_RIGHT"):  # If turning
    act = prefer_new([act, "SLOW_GO"])  # Prefer new turn; fallback to slow go
    mark(act)  # Mark decision
else:  # If not turning
    mark(act)  # Mark decision directly

print("NAV:OPTIMIZED", act)  # Print optimized action

Reflection: A tiny “memory” avoids same‑turn loops and feels smarter to watch.
Challenge:

  • Easy: Add “ROUTE:RESET” every 30 seconds to clear old memory.
  • Harder: Count turns per minute and reduce pulse time if turns exceed a limit.

Main project – Intelligent obstacle avoider

Blocks steps (with glossary)

  • Sensor fusion: IR side hits + ultrasonic front distance with thresholds and guards.
  • Mapping buffer: FREE/NEAR/BLOCK snapshots for front status smoothing.
  • Decision rules: STOP, TURN_LEFT/RIGHT, SLOW_GO, GO with cooldowns.
  • Exploration loop: Safe pulses, probes, and alternation to prevent hugging.
  • Optimization: Visited markers and recent preference to reduce cycles.

MicroPython code (mirroring blocks)

# Project 6.6 – Intelligent Obstacle Avoider

import machine  # Import machine for Pin control
import time  # Import time for microsecond timing and delays

# IR sensors
irL = machine.Pin(32, machine.Pin.IN)  # Left IR sensor
irC = machine.Pin(33, machine.Pin.IN)  # Center IR sensor
irR = machine.Pin(35, machine.Pin.IN)  # Right IR sensor
print("INIT: IR L=32 C=33 R=35")  # Confirm IR pins

# Ultrasonic pins
trig = machine.Pin(27, machine.Pin.OUT)  # Ultrasonic trigger
echo = machine.Pin(25, machine.Pin.IN)  # Ultrasonic echo
print("INIT: ULTRA TRIG=27 ECHO=25")  # Confirm ultrasonic pins

def ultra_cm():  # Measure distance (cm) with guards
    trig.value(0)  # Ensure trigger LOW
    time.sleep_us(3)  # Short settle
    trig.value(1)  # Trigger HIGH
    time.sleep_us(10)  # 10 us pulse
    trig.value(0)  # Trigger LOW
    t0 = time.ticks_us()  # Start timeout timer
    while echo.value() == 0:  # Wait for rising edge
        if time.ticks_diff(time.ticks_us(), t0) > 20000:  # 20 ms timeout
            return 999  # Return large value if no echo
    start = time.ticks_us()  # Record start
    t1 = start  # Initialize watchdog timestamp
    while echo.value() == 1:  # Wait while echo HIGH
        if time.ticks_diff(time.ticks_us(), t1) > 30000:  # 30 ms watchdog
            break  # Break if pulse too long
        t1 = time.ticks_us()  # Update watchdog time
    end = time.ticks_us()  # Record end
    dur = time.ticks_diff(end, start)  # Compute duration
    cm = dur // 58  # Convert to cm
    return cm  # Return distance

# Motor pins
L_IN1 = machine.Pin(18, machine.Pin.OUT)  # Left IN1
L_IN2 = machine.Pin(19, machine.Pin.OUT)  # Left IN2
R_IN3 = machine.Pin(5, machine.Pin.OUT)   # Right IN3
R_IN4 = machine.Pin(23, machine.Pin.OUT)  # Right IN4
print("INIT: MOTORS 18/19 5/23")  # Confirm motor pins

def motors_stop():  # Stop both motors
    L_IN1.value(0)  # Left IN1 LOW
    L_IN2.value(0)  # Left IN2 LOW
    R_IN3.value(0)  # Right IN3 LOW
    R_IN4.value(0)  # Right IN4 LOW
    print("MOVE:STOP")  # Print stop

def motors_forward(pulse=0.20):  # Forward pulse
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:FWD", pulse)  # Print forward
    time.sleep(pulse)  # Run pulse
    motors_stop()  # Stop

def motors_forward_slow(pulse=0.12):  # Slow forward pulse
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:FWD_SLOW", pulse)  # Print slow forward
    time.sleep(pulse)  # Run pulse
    motors_stop()  # Stop

def turn_left(pulse=0.16):  # Left turn pulse
    L_IN1.value(0)  # Left backward LOW
    L_IN2.value(1)  # Left backward HIGH
    R_IN3.value(1)  # Right forward HIGH
    R_IN4.value(0)  # Right forward LOW
    print("MOVE:LEFT", pulse)  # Print left turn
    time.sleep(pulse)  # Run pulse
    motors_stop()  # Stop

def turn_right(pulse=0.16):  # Right turn pulse
    L_IN1.value(1)  # Left forward HIGH
    L_IN2.value(0)  # Left forward LOW
    R_IN3.value(0)  # Right backward LOW
    R_IN4.value(1)  # Right backward HIGH
    print("MOVE:RIGHT", pulse)  # Print right turn
    time.sleep(pulse)  # Run pulse
    motors_stop()  # Stop

def probe_forward():  # Tiny forward probe
    print("NAV:PROBE")  # Print probe label
    motors_forward(pulse=0.10)  # Small forward pulse

near_cm = 30  # Threshold for NEAR
block_cm = 15  # Threshold for BLOCK
print("THRESH: NEAR", near_cm, "BLOCK", block_cm)  # Print thresholds

map_buf = []  # Buffer for front status snapshots
visited = set()  # Set of visited decisions
recent = []  # Recent decisions list
last_turn = ""  # Store last turn direction
cooldown_ms = 200  # Cooldown after STOP
last_stop_time = 0  # Timestamp of last STOP

def classify_front(irC_val, cm):  # Classify front status
    if (irC_val == 1) or (cm <= block_cm):  # If center blocked or too close
        status = "BLOCK"  # Block status
    elif cm <= near_cm:  # If near but not block
        status = "NEAR"  # Near status
    else:  # Otherwise free
        status = "FREE"  # Free status
    print("MAP:FRONT", status)  # Print status
    return status  # Return status

def decide_action(irL_val, irC_val, irR_val, cm):  # Decide next move
    if (irC_val == 1) or (cm <= block_cm):  # If front blocked
        act = "STOP"  # Choose stop
    elif irL_val == 1 and irR_val == 0:  # Left blocked only
        act = "TURN_RIGHT"  # Choose right turn
    elif irR_val == 1 and irL_val == 0:  # Right blocked only
        act = "TURN_LEFT"  # Choose left turn
    elif cm <= near_cm:  # Near obstacle
        act = "SLOW_GO"  # Choose slow go
    else:  # Clear path
        act = "GO"  # Choose normal go
    print("DECIDE:", act)  # Print decision
    return act  # Return decision

def mark(tag):  # Mark visited and recent decision
    visited.add(tag)  # Add to visited
    recent.append(tag)  # Append to recent list
    if len(recent) > 2:  # Limit recent size
        recent.pop(0)  # Remove oldest
    print("ROUTE:VISITED", list(visited))  # Print visited

def prefer_new(options):  # Prefer options not recently used
    for opt in options:  # Iterate options
        if opt not in recent:  # If not in recent
            print("ROUTE:CHOICE", opt)  # Print choice
            return opt  # Return choice
    print("ROUTE:FALLBACK", options[0])  # Print fallback
    return options[0]  # Return fallback

print("RUN: Intelligent avoider")  # Announce start
while True:  # Main navigation loop
    cm = ultra_cm()  # Measure distance
    front = classify_front(irC.value(), cm)  # Classify front status
    map_buf.append(front)  # Push to buffer
    if len(map_buf) > 5:  # Keep last 5 entries
        map_buf.pop(0)  # Drop oldest
    print("MAP:BUF", map_buf)  # Print buffer

    act = decide_action(irL.value(), irC.value(), irR.value(), cm)  # Decide next action

    if act == "STOP":  # If stop decided
        motors_stop()  # Stop immediately
        last_stop_time = time.ticks_ms()  # Record stop time
        time.sleep(cooldown_ms / 1000.0)  # Apply cooldown
        mark("STOP")  # Mark stop
        # Alternate turn preference after stop
        alt = "TURN_LEFT" if last_turn != "TURN_LEFT" else "TURN_RIGHT"  # Choose opposite of last turn
        act = alt  # Set act to alternate turn
        print("NAV:ALT_AFTER_STOP", act)  # Print alternate plan

    if act in ("TURN_LEFT", "TURN_RIGHT"):  # If turning
        choice = prefer_new([act, "SLOW_GO"])  # Prefer fresh turn
        mark(choice)  # Mark decision
        if choice == "TURN_LEFT":  # Execute left turn
            turn_left(0.18)  # Run left turn pulse
            last_turn = "TURN_LEFT"  # Save last turn
            probe_forward()  # Probe forward
        elif choice == "TURN_RIGHT":  # Execute right turn
            turn_right(0.18)  # Run right turn pulse
            last_turn = "TURN_RIGHT"  # Save last turn
            probe_forward()  # Probe forward
        else:  # If SLOW_GO fallback
            motors_forward_slow(0.12)  # Slow forward pulse
    elif act == "SLOW_GO":  # If slow go
        mark("SLOW_GO")  # Mark decision
        motors_forward_slow(0.12)  # Execute slow forward
    elif act == "GO":  # If normal go
        mark("GO")  # Mark decision
        motors_forward(0.20)  # Execute forward

    time.sleep(0.05)  # Small loop delay

External explanation

  • What it teaches: You fused fast IR hits with ultrasonic distance, smoothed status with a buffer, made clean decisions, explored safely with pulses and probes, and added a simple memory to avoid loops.
  • Why it works: IR gives instant “which side” info, ultrasonic gives “how far,” buffers reduce flukes, cooldowns prevent flip‑flops, and “prefer new” choices break cycles.
  • Key concept: “Sense → buffer → decide → act → learn.”

Story time

Your robot noses forward, senses a wall, and pivots like it knows the room. It tries a different route, probes ahead, and glides through—no frantic spinning, just smart, steady choices.


Debugging (2)

Debugging 6.6.1 – Does not detect obstacles of a certain color/texture

Problem: IR sensors miss glossy black or matte white surfaces.
Clues: IR_L/C/R stay 0 while ultrasonic shows small cm.
Broken code:

# Trust IR center alone for BLOCK
if irC_val == 1:
    status = "BLOCK"

Fixed code:

# Combine IR with ultrasonic threshold
if (irC_val == 1) or (cm <= block_cm):  # Use distance as a backup
    status = "BLOCK"  # Strong block even if IR fails

Why it works: Ultrasonic distance doesn’t care about color; combining sensors catches tricky surfaces.
Avoid next time: Use more than one sensor type for critical stops.

Debugging 6.6.2 – Cycles in navigation

Problem: Robot keeps turning the same way and loops.
Clues: Recent decisions show repeated “TURN_RIGHT”.
Broken code:

act = "TURN_RIGHT"  # Hard-coded preference

Fixed code:

act = prefer_new([act, "SLOW_GO"])  # Prefer not-recent actions
last_turn = "TURN_RIGHT"  # Track last turn and alternate after STOP

Why it works: Preference and alternation break repetitive loops and encourage fresh paths.
Avoid next time: Track history and avoid repeating the last choice too often.


Final checklist

  • IR and ultrasonic sensors print clear snapshots (IR_L/C/R and ULTRA_CM)
  • Front status buffer stabilizes decisions (FREE/NEAR/BLOCK)
  • Decisions choose STOP/TURN/SLOW_GO/GO with sensible thresholds
  • Exploration loop uses safe pulses and probes to test space
  • Route optimization reduces loops with visited and recent preferences

Extras

  • 🧠 Student tip: Log “DECIDE” and “MAP:FRONT” while driving different rooms—thresholds get easy to tune with data.
  • 🧑‍🏫 Instructor tip: Have teams draw a decision tree (STOP → TURN → PROBE → GO) before coding; it prevents chaotic movement.
  • 📖 Glossary:
    • Probe: A small, safe forward pulse to test if space is clear.
    • Cooldown: Short pause after STOP to avoid flip‑flop decisions.
    • Visited: Simple memory to avoid repeating the same turn again.
  • 💡 Mini tips:
    • Keep sensor heights matched; misalignment creates false side hits.
    • Re‑test ultrasonic thresholds when battery voltage changes.
    • Print short, labeled lines so classroom debugging stays readable.
On this page