13  Braitenberg Vehicles

In 60 Seconds

Braitenberg vehicles demonstrate that surprisingly intelligent-seeming behavior emerges from simple sensor-to-actuator connections. Same-side excitatory wiring creates avoidance (“fear”), cross-wired excitatory creates approach at speed (“aggression”), same-side inhibitory creates gentle approach and stop (“love”), and cross-wired inhibitory creates exploration. Many real IoT systems – thermostats, motion-activated lights, fan controllers – are essentially Braitenberg vehicles. Start simple before reaching for complex AI.

Key Concepts
  • Braitenberg Vehicle: A conceptual robotic vehicle where sensors connect directly to motors; demonstrates how complex behaviors (approach, avoidance, attraction) emerge from simple sensor-motor coupling rules without explicit programming
  • Ipsilateral (Direct) Coupling: A wiring pattern where each sensor drives the motor on the same side; depending on whether the connection is excitatory or inhibitory, produces vehicles that flee from or are attracted to stimulus sources
  • Contralateral (Crossed) Coupling: A wiring pattern where each sensor drives the motor on the opposite side; produces vehicles that turn toward or away from stimuli at oblique angles, creating steering and tracking behaviors
  • Emergent Behavior: Complex behavioral patterns arising from simple sensor-motor rules without explicit programming of the behavior; Braitenberg vehicles demonstrate intelligence emerging from reactive systems
  • Reactive Architecture: A robot control architecture with no internal state or planning — sensors connect directly to actuators through fixed rules; computationally trivial but capable of robust real-time behavior
  • Phototaxis: Movement toward (positive) or away from (negative) a light source; a classic Braitenberg behavior demonstrating how a single sensor-motor wiring decision determines approach versus avoidance
  • Embodied Intelligence: The principle that intelligence arises from the interaction between body morphology, sensor placement, and environment — not solely from computation; Braitenberg vehicles are a classic demonstration
  • Sensor Fusion in Reactive Systems: Combining multiple sensor inputs in a Braitenberg vehicle to produce richer behaviors; for example, approaching a light source only when no obstacles are in the path by combining light and proximity sensors

Learning Objectives

After completing this chapter, you will be able to:

  • Explain how Braitenberg vehicles map sensor inputs to actuator outputs using wiring topology and polarity
  • Design simple reactive systems using direct sensor-to-actuator connections
  • Predict emergent behaviors from different sensor-actuator coupling configurations
  • Evaluate when Braitenberg-style reactive control is sufficient versus when AI/ML is required

13.1 Prerequisites

13.2 From Sensors to Behavior: The Braitenberg Model

~20 min | Intermediate | P06.C08.U04

Before diving into complex AI and machine learning, understand that simple sensor-actuator connections can create surprisingly intelligent-seeming behavior. Valentino Braitenberg’s thought experiments (1984) showed that vehicles with just sensors and motors can exhibit behaviors that look like fear, aggression, love, and exploration.

This matters for IoT because: - Simple is often better (fewer failure points) - Reactive systems respond faster than AI - You can build useful devices with basic logic

13.3 The Braitenberg Vehicles

Braitenberg imagined simple vehicles with sensors connected directly to motors. The simplest, Vehicle 1, has a single sensor driving a single motor: more stimulus means more speed. The more interesting behaviors emerge with two sensors and two motors, where the connection type determines the behavior:

Braitenberg vehicle types showing different sensor-motor connections: Vehicle 1 (single sensor, single motor -- more stimulus means faster), Vehicle 2a Fear (same-side excitatory, runs from light), Vehicle 2b Aggression (cross-wired excitatory, attacks light), Vehicle 3a Love (same-side inhibitory, approaches and stays near), Vehicle 3b Explorer (cross-wired inhibitory, avoids obstacles)

Braitenberg vehicles showing sensor-motor connection types

13.3.1 Vehicle Behaviors

Vehicle Connection Behavior IoT Example
2a: Coward (Fear) Same-side, excitatory Runs away from stimulus Light-avoiding robot
2b: Aggression Cross-wired, excitatory Attacks stimulus Line-following robot
3a: Love Same-side, inhibitory Approaches and stays near Plant-watering robot
3b: Explorer Cross-wired, inhibitory Explores, avoids obstacles Roomba-like navigation

13.3.2 Interactive: Braitenberg Motor Speed Calculator

Adjust the sensor readings and wiring configuration to see how different Braitenberg vehicles respond. Observe how the same sensor values produce completely different motor speeds and turning behavior depending on wiring topology and polarity.

The calculator above uses a pure Braitenberg model for excitatory modes (motor = sensor * gain, no base speed), matching the original theoretical formulation. The worked example later in this chapter adds a base speed offset (motor = base_speed + sensor * gain) to overcome real motor friction. Both are valid – the base speed is a practical engineering addition, not a change to the Braitenberg wiring logic. Inhibitory modes use base speed in both the calculator and examples.

13.3.3 Code Example: Fear Behavior

# Braitenberg Vehicle 2a: Fear (runs from light)
# Left sensor -> Left motor, Right sensor -> Right motor (same-side, excitatory)
# Note: Uses generic 10-bit ADC range (0-1023). ESP32 examples later use 12-bit (0-4095).

def fear_behavior():
    while True:
        left_light = read_sensor("left_ldr")
        right_light = read_sensor("right_ldr")

        # Same-side connection: more light = faster motor
        left_motor.speed = map_value(left_light, 0, 1023, 0, 255)
        right_motor.speed = map_value(right_light, 0, 1023, 0, 255)

        # Result: Robot runs AWAY from light
        # (brighter side spins faster, turning away from light)

13.3.4 Code Example: Aggression Behavior

# Braitenberg Vehicle 2b: Aggression (attacks light)
# Left sensor -> Right motor, Right sensor -> Left motor (cross-wired, excitatory)
# Note: Uses generic 10-bit ADC range (0-1023). ESP32 examples later use 12-bit (0-4095).

def aggression_behavior():
    while True:
        left_light = read_sensor("left_ldr")
        right_light = read_sensor("right_ldr")

        # Cross-wired connection
        left_motor.speed = map_value(right_light, 0, 1023, 0, 255)
        right_motor.speed = map_value(left_light, 0, 1023, 0, 255)

        # Result: Robot ATTACKS light source
        # (brighter side makes opposite motor faster, turning toward light)
How It Works: Braitenberg Vehicle 2b (Aggression)

The aggressive light-seeking vehicle uses cross-wired excitatory connections:

  1. Left light sensor detects brightness on left side
  2. Signal crosses to right motor (cross-wired)
  3. Right motor speeds up when left sensor sees light (excitatory)
  4. Vehicle turns left toward the light source
  5. Process repeats continuously, creating approach behavior

Why it works: When light is on the left, the right motor spins faster than the left motor, causing a differential drive turn toward the stimulus. The brighter the light, the faster the turn (excitatory connection). Result: vehicle “attacks” the light source.

Real IoT example: A line-following robot uses the same cross-wired principle – if the left IR sensor sees the dark line, the right motor speeds up to steer the robot left back onto the line, and vice versa. The stronger the deviation, the harder the correction (excitatory connection).

Try It: Braitenberg Vehicle Visual Simulator

Watch a top-down SVG vehicle respond to a light source in real time. Drag the light position slider to see how different wiring configurations cause the vehicle to turn toward or away from the stimulus.

13.4 IoT Applications of Braitenberg Principles

13.4.1 Smart Lighting System

# Adaptive lighting using cross-wired inhibitory mapping
# Each sensor controls the opposite LED -- dark areas get compensated

def adaptive_lighting():
    left_ambient = read_lux_sensor("left")
    right_ambient = read_lux_sensor("right")

    # Cross-wired, inhibitory: low ambient -> high LED output
    right_led.brightness = map_inverse(left_ambient, 0, 1000, 0, 100)
    left_led.brightness = map_inverse(right_ambient, 0, 1000, 0, 100)

    # Result: Room maintains even lighting
    # Darker areas get more artificial light

13.4.2 Temperature-Seeking Robot

# Robot that finds and stays near heat sources
# (like a cat finding a sunny spot)

def heat_seeker():
    while True:
        left_temp = read_thermistor("left")
        right_temp = read_thermistor("right")

        # Same-side, inhibitory (love behavior)
        # Warmer side slows its own motor -> vehicle turns toward heat
        # As both sensors increase near source, both motors slow -> stops
        left_motor.speed = BASE_SPEED - map_value(left_temp, 20, 40, 0, 200)
        right_motor.speed = BASE_SPEED - map_value(right_temp, 20, 40, 0, 200)

        # Result: Approaches heat source and slows down near it
Try It: IoT Sensor-Actuator Mapping Explorer

Choose a real-world IoT application and adjust the sensor reading to see how different Braitenberg wiring types translate into actuator output. This demonstrates that many everyday IoT devices use simple reactive mappings.

13.5 Why This Matters for IoT

Case Study: iRobot Roomba’s Braitenberg-Style Navigation (2002-2015)

Background: The original iRobot Roomba (models 400-600 series) used a reactive navigation system directly inspired by Braitenberg vehicle principles, rather than the SLAM-based mapping used in later models. With just 4 sensors and 2 drive wheels, the Roomba demonstrated that useful cleaning behavior emerges from simple sensor-actuator coupling.

Sensor-Actuator Mapping:

Sensor Behavior When Triggered Braitenberg Equivalent
Front bumper (left hit) Reverse 2 cm, rotate right 30-90 degrees random Fear (same-side excitatory avoidance)
Front bumper (right hit) Reverse 2 cm, rotate left 30-90 degrees random Fear (same-side excitatory avoidance)
Cliff sensor (IR) Immediate reverse, rotate 180 degrees Fear (strong excitatory response to danger stimulus)
Wall-following IR Maintain 3-5 cm distance from wall on right side Love (same-side inhibitory – approaches wall and stays near)

The Spiral-Wall-Random Algorithm: The Roomba combined three Braitenberg-style behaviors into a cleaning strategy:

  1. Spiral outward (excitatory same-side): Both wheels accelerate at slightly different rates, creating an expanding spiral until bumper contact
  2. Wall-follow (inhibitory same-side): After bumper hit near wall, right IR sensor maintains constant distance – the “love” behavior that keeps it tracing the room perimeter
  3. Random bounce (excitatory with randomization): After bumper hits in open space, random turn angle prevents repetitive loops

Why it worked without a map:

  • Coverage guarantee: Probabilistic analysis shows that random-bounce + wall-follow achieves high floor coverage (typically > 90%) in rectangular rooms within a single cleaning cycle
  • No localization needed: The robot never knows where it is – it simply reacts to stimuli. This eliminated the need for cameras, LIDAR, or expensive processors
  • Cost impact: The reactive Roomba’s BOM was reportedly under $100 (retailing at $199), far less than SLAM-based competitors. Braitenberg-style simplicity enabled the first mass-market robot vacuum

Limitations that eventually drove the shift to SLAM:

Problem Root Cause Braitenberg Limitation
Misses spots in L-shaped rooms Random bounce is probabilistic, not systematic No spatial memory – reactive systems cannot plan coverage
Re-cleans already-clean areas No knowledge of where it has been Same stimulus always triggers same response regardless of history
Gets stuck under furniture Bumper-only obstacle model Cannot anticipate obstacles before contact
45+ minute clean time for 50m2 Redundant traversals Systematic path planning achieves same coverage in 20 minutes

Design lesson: The Roomba’s evolution from Braitenberg-style reactive navigation (2002) to SLAM-based mapping (Roomba 980, 2015) illustrates the principle from this chapter: start simple, add complexity only when simple fails. iRobot sold tens of millions of reactive Roombas before adding mapping. The reactive approach was “good enough” for 13 years – and understanding WHY it worked (sensor-actuator coupling creates emergent behavior) helps you recognize when your IoT system genuinely needs AI versus when a simple reactive response will suffice.

13.6 Design Principles from Braitenberg

  1. Simple connections create complex behavior - Emergent intelligence from direct wiring
  2. Sensor placement matters - Position determines what the system “sees”
  3. Connection polarity affects outcome - Excitatory vs inhibitory
  4. Cross-wiring vs same-side wiring - Determines approach vs avoidance
  5. Start simple, add complexity only when needed - Prototype reactively before adding AI
Key Takeaway

Before writing complex AI code, ask whether a simple sensor-to-actuator mapping can achieve the desired behavior. Braitenberg’s insight was that direct connections between sensors and motors (varying only wiring topology and polarity) can produce behaviors resembling fear, aggression, exploration, and attraction. Many practical IoT systems are essentially Braitenberg vehicles – and simpler designs have fewer failure points.

Sammy the Sensor built a tiny robot car with two light sensors (eyes) and two motors (wheels). He wanted to show the Sensor Squad something amazing.

“Watch this!” Sammy connected the left eye to the left wheel and the right eye to the right wheel. When he shined a flashlight at the robot, the side facing the light spun its wheel faster, and the robot turned AWAY from the light! “It looks scared!” shouted Lila the LED.

Then Sammy swapped the wires: left eye to RIGHT wheel, right eye to LEFT wheel. Now the robot drove TOWARD the light! “It is attacking the flashlight!” Max laughed.

“But here is the best part,” Sammy whispered. He put the wires back to same-side (left eye to left wheel, right eye to right wheel) but reversed the effect so that more light made the motors SLOWER instead of faster. Now the robot gently approached the light and stopped next to it. “It loves the light – like a cat finding a sunny spot!” said Bella the Battery.

“This is called a Braitenberg vehicle,” Max explained. “Just by changing how the wires connect, we get completely different behaviors – no AI needed! A thermostat works the same way: temperature sensor directly controls the heater. Simple is powerful!”

Scenario: Create an IoT plant pot that automatically rotates toward the nearest window to maximize sunlight exposure for the plant. Use Braitenberg vehicle principles for simple, reliable behavior.

Requirements:

  • Detect light direction using two LDR sensors (left and right sides of pot)
  • Rotate base using two small DC motors (differential drive)
  • Maximize sunlight while minimizing complex code and battery usage

Step 1: Choose Braitenberg wiring topology

We want the pot to approach and orient toward light → Use cross-wired, excitatory connection (Vehicle 2b: Aggression)

Circuit connections:

Left LDR sensor → Right motor (cross-wired)
Right LDR sensor → Left motor (cross-wired)
More light → Faster motor (excitatory)

Behavior:

  • If light is on the left, right motor speeds up → pot turns left toward light
  • If light is on the right, left motor speeds up → pot turns right toward light
  • When centered on light source, both motors run at equal speed → pot faces light directly

Step 2: Implement with ESP32 (MicroPython)

from machine import Pin, ADC, PWM
import time

# LDR sensors (analog)
left_ldr = ADC(Pin(34))
right_ldr = ADC(Pin(35))
left_ldr.atten(ADC.ATTN_11DB)  # 0-3.3V range
right_ldr.atten(ADC.ATTN_11DB)

# Motors (PWM)
right_motor = PWM(Pin(25), freq=1000)
left_motor = PWM(Pin(26), freq=1000)

# Braitenberg Vehicle 2b: Aggression (light-seeking)
def light_seeking_behavior():
    while True:
        # Read light sensors (higher value = more light)
        left_light = left_ldr.read()   # 0-4095
        right_light = right_ldr.read()

        # Cross-wired, excitatory connection
        # Scale to motor speed (0-1023 duty cycle)
        base_speed = 200  # Minimum speed to overcome friction
        gain = 0.15       # Sensitivity to light difference

        right_speed = base_speed + int(left_light * gain)   # Left sensor → Right motor
        left_speed = base_speed + int(right_light * gain)   # Right sensor → Left motor

        # Apply motor speeds
        right_motor.duty(min(1023, max(0, right_speed)))
        left_motor.duty(min(1023, max(0, left_speed)))

        time.sleep_ms(100)  # 10 Hz update rate

light_seeking_behavior()

Step 3: Measured behavior

Light Position Left LDR Right LDR Left Motor Right Motor Pot Movement
Far left (90° off) 800 100 215 320 Turns left rapidly
45° left 600 300 245 290 Turns left moderately
Centered 500 500 275 275 Moves straight forward
45° right 300 600 290 245 Turns right moderately
Far right (90° off) 100 800 320 215 Turns right rapidly

Step 4: Add dead zone to prevent jitter

When the pot is nearly centered, small sensor noise causes oscillation. Add a dead zone:

# Only rotate if light difference exceeds threshold
light_diff = abs(left_light - right_light)
if light_diff < 100:  # Within ~2.4% of 4095 max range -- close enough!
    # Stop motors when centered
    left_motor.duty(0)
    right_motor.duty(0)
else:
    # Apply Braitenberg behavior
    right_motor.duty(base_speed + int(left_light * gain))
    left_motor.duty(base_speed + int(right_light * gain))

Result: The plant pot smoothly rotates toward the brightest light source and stops when aligned, using only ~50 lines of code and no AI/ML. Total power: 2× 5V motors (100mA each) + ESP32 (80mA) = 280mA @ 5V during rotation.

Battery life (4x AA batteries with 5V regulator, 2500 mAh): - Assume 5 minutes of rotation per day (tracking sun movement) - Daily energy: 280 mA x (5/60) hours = 23.3 mAh/day - Battery life: 2500 mAh / 23.3 mAh = 107 days (~3.5 months)

Battery life depends on duty cycle. For 5 minutes of 280 mA rotation per day:

\[E_{daily} = I \times t = 280 \text{ mA} \times \frac{5}{60} \text{ h} = 23.3 \text{ mAh/day}\]

With 2500 mAh AA batteries (4x in series = 6V, regulated to 5V):

\[\text{Battery life} = \frac{2500 \text{ mAh}}{23.3 \text{ mAh/day}} = 107 \text{ days}\]

If the pot also sleeps (10 µA) for 23.92 hours/day: \(E_{sleep} = 0.01 \times 23.92 = 0.24\) mAh/day, increasing total to 23.6 mAh/day (still 106 days). Motor energy dominates — optimizing sleep current has negligible impact when actuators run even briefly.

13.6.1 Interactive: Battery Life Calculator for Reactive IoT Devices

Key insight: This Braitenberg-style reactive system is simpler, cheaper, and more reliable than using a camera + OpenCV + servo control + compass for the same task.

System Requirement Reactive (Braitenberg-style) AI/ML Required
Response to immediate stimulus ✓ Thermostat turns on heater when T < setpoint Not needed
Pattern recognition ✗ Cannot detect “person” vs “dog” in camera feed ✓ Requires ML image classification
Memory of past events ✗ Cannot remember “this room was cleaned 1 hour ago” ✓ Requires state tracking or ML
Multi-step planning ✗ Cannot plan “optimal delivery route for 50 packages across a city” ✓ Requires optimization algorithms or ML-based planning
Adaptation to user behavior ✗ Cannot learn “user prefers 22°C on weekdays, 24°C on weekends” ✓ Requires ML or statistical modeling
Real-time response (<100ms) ✓ Direct sensor-to-actuator is fastest possible AI adds latency (inference time)
Low-power operation (<1mW avg) ✓ Simple threshold checks run on wake-from-sleep AI inference drains battery (10-100mW)
Fail-safe behavior ✓ Loss of control → actuators go to safe default state AI failure modes are unpredictable

Design decision tree:

Question 1: Can you describe the desired behavior as “if sensor X crosses threshold Y, then actuator Z does W”? - Yes → Use reactive control (Braitenberg-style) - No → Go to Question 2

Question 2: Do you need the system to recognize complex patterns (faces, gestures, anomalies)? - Yes → AI/ML required - No → Go to Question 3

Question 3: Does the system need to remember previous states or predict future states? - Yes → Use state machine or AI (depending on complexity) - No → Use reactive control

Question 4: Is real-time response critical (<100ms latency)? - Yes → Reactive control (AI adds 50-500ms inference delay) - No → Either works, choose based on complexity

Worked examples:

IoT System Correct Approach Why
Smart thermostat Reactive If T < setpoint-1°C → turn ON heater. If T > setpoint+1°C → turn OFF. No ML needed.
Person detection for security camera AI (computer vision) Must distinguish “person” from “cat” or “tree shadow” → requires ML image classification
Smart sprinkler Reactive with timer If soil_moisture < 30% AND time_of_day = 6am → water for 10 minutes. No ML needed.
Predictive HVAC AI (time-series forecasting) Learn “office is empty on Fridays” → pre-cool Thursday evening instead of Friday morning → requires ML
Emergency stop button Reactive Button press → IMMEDIATELY cut power to motor. No latency tolerance for AI.
Gesture-controlled lights AI (gesture recognition) Must classify hand wave from random arm movement → requires ML with accelerometer/camera

Cost comparison (ESP32-based system):

Feature Reactive Control AI/ML
Code size 1-5 KB 50-500 KB (model weights)
RAM usage <1 KB 10-100 KB (inference)
Power (active) 80 mA (ESP32 running loop) 120-180 mA (ESP32 + inference)
Power (sleep) 10 µA (wake-on-sensor) Cannot easily sleep (must monitor continuously)
Development time 1-2 days 1-4 weeks (data collection + training + integration)
Failure modes Predictable (threshold tuning) Unpredictable (adversarial inputs, dataset drift)

Key recommendation: Start with reactive Braitenberg-style control. Only add AI/ML when the reactive approach provably fails to meet requirements. Many commercial IoT products use pure reactive logic:

  • Basic bimetallic thermostat: Purely reactive – metal strip bends at setpoint, opens/closes circuit (no electronics at all)
  • Philips Hue motion sensors: Reactive (motion → light ON)
  • Ring doorbell (basic): Reactive (button press → chime)
  • iRobot Roomba 400-600: Reactive Braitenberg-style navigation (bump → turn)

When AI is genuinely needed: Voice assistants (Alexa, Google Home), facial recognition locks, predictive maintenance (vibration analysis), anomaly detection in network traffic.

Common Mistake: Over-Complicating Behavior That Simple Sensor-Actuator Mapping Can Solve

The mistake: A student team designs an “AI-powered smart fan” that uses a neural network trained on temperature sensor data to predict when the user will feel hot and pre-emptively adjust fan speed. After 3 weeks of data collection and model training, the fan works inconsistently, drains battery in 4 hours due to continuous inference, and occasionally runs at full speed when the room is already cold (model overfitting).

The simple solution they ignored: A Braitenberg-style direct sensor-to-actuator mapping

# "AI-powered" version: 250 lines of TensorFlow Lite inference
# vs Braitenberg version: 8 lines of code

def smart_fan_behavior():
    temp = read_temperature_sensor()  # °C

    # Direct temperature-to-speed mapping
    if temp < 22:
        fan_speed = 0          # Off
    elif temp < 26:
        fan_speed = (temp - 22) * 25  # 0-100% linearly from 22-26°C
    else:
        fan_speed = 100        # Max speed

    set_fan_pwm(fan_speed)

Why this works better:

Aspect AI/ML Approach Braitenberg Reactive Approach
Response time 200-500ms (model inference) <10ms (direct PWM)
Battery life 4 hours (continuous monitoring + inference) 24+ hours (simple thresholds, sleep between readings)
Predictability Unpredictable (model may hallucinate) 100% deterministic
Code complexity 250 lines (TensorFlow Lite + data pipeline) 8 lines (if-else statements)
User experience Sometimes runs when cold (false positives) Always behaves as expected
Development time 3 weeks (data collection + training + tuning) 1 hour

When the team tested both versions:

Test Condition AI Version Reactive Version
Room at 24°C Fan at 60% (correct) Fan at 50% (correct)
Room at 28°C Fan at 85% (underestimated) Fan at 100% (correct)
Room at 20°C Fan at 40% (false activation!) Fan at 0% (correct)
Sudden temperature spike (door opened) Delayed response (waits for prediction window) Immediate response (<1 second)

Root cause of AI failure: The neural network was trained on slow temperature changes (day/night cycles). It failed to generalize to fast changes (door opening) and occasionally misclassified cold temperatures as “user is about to feel hot soon” due to overfitting on limited training data.

Lessons from Braitenberg:

  1. Simple sensor-actuator mappings create surprisingly effective behavior
  2. Direct response is faster and more reliable than prediction
  3. Predictability matters more than “intelligence” for IoT appliances

When ML genuinely improves the system: Add ML AFTER proving the reactive system works, to optimize edge cases:

# Hybrid approach: Reactive base + ML optimization
def hybrid_smart_fan():
    temp = read_temperature_sensor()
    humidity = read_humidity_sensor()

    # Base reactive behavior (always works)
    base_speed = calculate_braitenberg_speed(temp)

    # ML refinement (optional, only if conditions are normal)
    if model_confidence_high():
        comfort_adjustment = ml_predict_comfort(temp, humidity, time_of_day)
        final_speed = base_speed + comfort_adjustment
    else:
        final_speed = base_speed  # Fall back to reactive when uncertain

    set_fan_pwm(clamp(final_speed, 0, 100))

Key takeaway: Before implementing AI/ML for an IoT system, ALWAYS prototype with Braitenberg-style reactive control first. If the reactive version solves 80% of use cases, ship it. Only add ML if there is a measurable user benefit (not just “because we can”).

13.7 Code Example: Multi-Behavior Robot with Mode Switching

This MicroPython example implements a complete Braitenberg vehicle on an ESP32 that switches between fear, aggression, and love modes using a button. This is a practical exercise for understanding how wiring topology creates different behaviors:

# ESP32 Braitenberg Vehicle with mode switching
# Hardware: 2x LDR sensors, 2x DC motors (via L298N), 1x button
from machine import Pin, ADC, PWM
import time

# Sensor pins (analog)
left_sensor = ADC(Pin(34))
right_sensor = ADC(Pin(35))
left_sensor.atten(ADC.ATTN_11DB)   # Full 3.3V range
right_sensor.atten(ADC.ATTN_11DB)

# Motor PWM pins
left_motor = PWM(Pin(25), freq=1000)
right_motor = PWM(Pin(26), freq=1000)

# Mode button
button = Pin(13, Pin.IN, Pin.PULL_UP)
mode = 0  # 0=fear, 1=aggression, 2=love
MODES = ['FEAR', 'AGGRESSION', 'LOVE']

def scale(value, in_min, in_max, out_min, out_max):
    """Map sensor reading to motor speed."""
    return int((value - in_min) * (out_max - out_min)
               / (in_max - in_min) + out_min)

def set_motors(left_speed, right_speed):
    """Set motor speeds (0-1023)."""
    left_motor.duty(max(0, min(1023, left_speed)))
    right_motor.duty(max(0, min(1023, right_speed)))

while True:
    # Check for mode change
    if not button.value():
        mode = (mode + 1) % 3
        print(f"Mode: {MODES[mode]}")
        time.sleep_ms(300)  # Debounce

    left = left_sensor.read()    # 0-4095
    right = right_sensor.read()

    if mode == 0:  # FEAR: same-side, excitatory
        set_motors(scale(left, 0, 4095, 0, 800),
                   scale(right, 0, 4095, 0, 800))

    elif mode == 1:  # AGGRESSION: cross-wired, excitatory
        set_motors(scale(right, 0, 4095, 0, 800),
                   scale(left, 0, 4095, 0, 800))

    elif mode == 2:  # LOVE: same-side, inhibitory
        set_motors(800 - scale(left, 0, 4095, 0, 600),
                   800 - scale(right, 0, 4095, 0, 600))

    time.sleep_ms(50)  # 20 Hz control loop

Behavior observations when testing:

Mode Flashlight on left Flashlight on right Flashlight centered
Fear Turns right (away) Turns left (away) Drives straight ahead fast
Aggression Turns left (toward) Turns right (toward) Drives straight into light
Love Turns left (toward) slowly Turns right (toward) slowly Slows down, stops near light
Try It: Multi-Mode Behavior Comparison

Compare all four Braitenberg vehicle behaviors side by side. Set a single light stimulus and observe how each wiring configuration produces a completely different motor response and turning direction from the same sensor input.

13.8 Summary

Key takeaways from Braitenberg vehicles:

  1. Simple sensor-actuator links create emergent behavior – wiring topology and polarity alone produce fear, aggression, love, and exploration
  2. Connection type determines behavior – same-side vs cross-wired sets direction; excitatory vs inhibitory sets intensity
  3. Many IoT systems are essentially Braitenberg vehicles – thermostats, motion lights, and fan controllers use direct sensor-actuator mapping
  4. Consider reactive design before complex AI – the majority of commercial IoT products use purely reactive logic for their core function

Goal: Build Vehicle 2b that chases a flashlight.

Components:

  • ESP32 + L298N motor driver
  • 2× LDR photoresistors (left/right sensors)
  • 2× DC motors + wheels
  • 9V battery

Wiring:

Left LDR  → ADC pin 34 → Right motor (cross-wired)
Right LDR → ADC pin 35 → Left motor (cross-wired)
More light = faster motor (excitatory)

Expected behavior: Robot turns toward flashlight and drives into it

Goal: Build a mobile heater that moves toward warm areas and stays there (for temperature monitoring or co-locating with existing heat sources).

Components:

  • 2x thermistors (left/right temperature sensors)
  • 2x DC motors
  • Temperature logger / display

Wiring topology:

  • Same-side inhibitory (love behavior)
  • Warm side (high temp reading) inhibits same-side motor more, slowing it -> turns toward warmth
  • As it reaches the warm zone, both sensors read high, both motors slow -> stops near the heat source

Why this works: Same-side inhibitory means motor = base_speed - sensor * gain. High stimulus (warmth) produces high inhibition, slowing the motor on that side. The opposite motor runs faster, turning the vehicle toward the warm area. Near the source, both sensors read high, both motors slow, and the vehicle stops – classic “love” behavior.

Real application: A mobile sensor platform that autonomously navigates to warm zones for thermal monitoring, or a robot that finds and stays near a charging station emitting heat.

Goal: Robot switches between fear/aggression/love modes using a button.

Modes:

  1. Fear mode (same-side excitatory): Runs from light
  2. Aggression mode (cross-wired excitatory): Attacks light
  3. Love mode (same-side inhibitory): Approaches and stops near light

Challenge: Implement smooth transitions between modes, add LED indicators for current mode

Bonus: Add a fourth mode: “Explorer” (cross-wired inhibitory) for obstacle avoidance (Roomba-like)

13.9 Concept Relationships

Core Concept Related Concepts Why It Matters
Cross-Wired vs Same-Side Approach vs Avoidance Determines direction of response
Excitatory vs Inhibitory Speed Up vs Slow Down Determines intensity of response
Emergent Behavior Simple Rules, Complex Outcomes Intelligence appears without programming it
Reactive Control No Memory, Fast Response Simpler than AI, often sufficient

Common Pitfalls

An excitatory connection increases motor speed when the sensor signal increases; an inhibitory connection decreases motor speed. Swapping these causes vehicles to move opposite to intended — approach instead of avoid. Always simulate the behavior on paper before wiring physical motors.

If the sensor output range drives motor speed directly without scaling, the motor may always run at maximum or minimum speed with little intermediate behavior. Add a scaling function between the sensor output and the motor driver to use the full behavioral range.

Physical motors have inertia and time constants (50-500 ms) that lag behind rapidly changing sensor inputs, causing jittery oscillatory motion. Add a low-pass filter to the sensor input or a ramp-rate limit on the motor command to achieve smooth behavior.

A vehicle controlled by a single light sensor fails unpredictably when walls, reflections, or shadows create contradictory stimuli. Add a second sensor type (proximity, IR distance) to provide context and enable more situation-aware behaviors.

13.10 What’s Next

Now that you can map sensor inputs to actuator outputs using Braitenberg principles:

Next Topic Description
Infrastructure Sensing Leverage existing infrastructure as sensor inputs for reactive systems
Calibration Techniques Calibrate sensors to ensure accurate readings for reliable actuator mappings
Common IoT Sensors Survey popular sensor types used in real-world Braitenberg-style IoT devices
Sensor Classification Review how sensors are categorized by measurement principle and output type
Signal Processing Apply filtering and conditioning to sensor data before actuator mapping