14

Lesson 14: Basic miniAuto Programming

Programming your robot for autonomous behavior

Important: Code Compatibility Notice

Some code examples in this lesson reference #include "miniAuto.h" and miniAuto.* functions. This is a custom library that may not be available.

✅ Use the working code from Section 1 - it uses standard Arduino libraries and will compile successfully. The other examples are for conceptual understanding only.

Learning Objectives

By the end of this lesson, students will:

  • Use Arduino functions for robot control effectively
  • Create autonomous navigation programs
  • Implement sensor-based decision making
  • Debug and optimize robot behavior

Skills Developed:

  • Robotics library usage
  • Autonomous system design
  • Real-time debugging techniques

Lesson Content

1 miniAuto Library Functions (20 minutes)

Essential miniAuto Functions:

Movement Functions:
  • moveForward(speed)
  • moveBackward(speed)
  • turnLeft(speed)
  • turnRight(speed)
  • stop()
Sensor Functions:
  • getDistance()
  • getLineSensor()
  • getBatteryVoltage()
  • getEncoderCount()
  • isButtonPressed()
/**
 * @file miniAuto_obstacle_avoidance.ino
 * @brief Basic Obstacle Avoidance Program using Standard Arduino Libraries
 * @author miniAuto Team / Hiwonder
 * @version V1.0
 * @date 2024-04-22
 */

#include <Arduino.h>

// Motor control pins
const static uint8_t motorpwmPin[4] = {10, 9, 6, 11};        // Motor speed control pins
const static uint8_t motordirectionPin[4] = {12, 8, 7, 13};  // Motor direction control pins

// Sensor pins
const int trigPin = 2;
const int echoPin = 3;
const int ledPin = 13;

// Function declarations
void Motor_Init(void);
void Velocity_Controller(uint16_t angle, uint8_t velocity, int8_t rot, bool drift);
void Motors_Set(int8_t Motor_0, int8_t Motor_1, int8_t Motor_2, int8_t Motor_3);
float getUltrasonicDistance();
void setStatusLED(bool state);

void setup() {
    Serial.begin(9600);
    Serial.println("🤖 miniAuto Obstacle Avoidance Program");
    
    // Initialize motors
    Motor_Init();
    
    // Initialize ultrasonic sensor
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    
    // Initialize LED
    pinMode(ledPin, OUTPUT);
    
    // Startup sequence
    Serial.println("System initialized - Starting obstacle avoidance...");
    setStatusLED(true);
    delay(1000);
    setStatusLED(false);
}

void loop() {
    // Get distance reading
    float distance = getUltrasonicDistance();
    
    // Display status
    Serial.print("Distance: ");
    Serial.print(distance);
    Serial.println(" cm");
    
    // Simple obstacle avoidance behavior
    if (distance > 30) {
        // Clear path - move forward
        Serial.println("→ Moving forward");
        Velocity_Controller(0, 60, 0, 0);  // Move forward at 60% speed
        setStatusLED(false);  // LED off = good
    } else if (distance > 15) {
        // Obstacle detected - slow down
        Serial.println("⚠️ Slowing down");
        Velocity_Controller(0, 30, 0, 0);  // Move forward at 30% speed
        setStatusLED(true);   // LED on = caution
    } else {
        // Obstacle too close - stop and turn
        Serial.println("🚫 Obstacle! Turning right");
        Velocity_Controller(0, 0, 0, 0);   // Stop
        delay(200);
        Velocity_Controller(0, 0, -50, 0); // Turn right in place
        delay(800);
        setStatusLED(false);
    }
    
    delay(100);  // Small delay for stability
}

// Motor initialization function
void Motor_Init(void) {
    for(uint8_t i = 0; i < 4; i++) {
        pinMode(motordirectionPin[i], OUTPUT);
    }
    Velocity_Controller(0, 0, 0, 0);  // Start with motors stopped
}

/**
 * @brief Speed control function for omnidirectional movement
 * @param angle     Controls robot motion direction (0-359°, front=0°, counterclockwise positive)
 * @param velocity  Controls robot speed (0-100)
 * @param rot       Controls rotation speed (-100 to 100, positive=counterclockwise)
 * @param drift     Enables drift mode (0=normal, 1=drift)
 */
void Velocity_Controller(uint16_t angle, uint8_t velocity, int8_t rot, bool drift) {
    int8_t velocity_0, velocity_1, velocity_2, velocity_3;
    float speed = 1;
    angle += 90;
    float rad = angle * PI / 180;
    
    if (rot == 0) speed = 1;
    else speed = 0.5; 
    
    velocity /= sqrt(2);
    
    if (drift) {
        velocity_0 = (velocity * sin(rad) - velocity * cos(rad)) * speed;
        velocity_1 = (velocity * sin(rad) + velocity * cos(rad)) * speed;
        velocity_2 = (velocity * sin(rad) - velocity * cos(rad)) * speed - rot * speed * 2;
        velocity_3 = (velocity * sin(rad) + velocity * cos(rad)) * speed + rot * speed * 2;
    } else {
        velocity_0 = (velocity * sin(rad) - velocity * cos(rad)) * speed + rot * speed;
        velocity_1 = (velocity * sin(rad) + velocity * cos(rad)) * speed - rot * speed;
        velocity_2 = (velocity * sin(rad) - velocity * cos(rad)) * speed - rot * speed;
        velocity_3 = (velocity * sin(rad) + velocity * cos(rad)) * speed + rot * speed;
    }
    Motors_Set(velocity_0, velocity_1, velocity_2, velocity_3);
}

/**
 * @brief PWM and motor direction setting function
 */
void Motors_Set(int8_t Motor_0, int8_t Motor_1, int8_t Motor_2, int8_t Motor_3) {
    int8_t pwm_set[4];
    int8_t motors[4] = {Motor_0, Motor_1, Motor_2, Motor_3};
    bool direction[4] = {1, 0, 0, 1};
    
    for(uint8_t i = 0; i < 4; ++i) {
        if(motors[i] < 0) direction[i] = !direction[i];
        else direction[i] = direction[i];

        if(motors[i] == 0) pwm_set[i] = 0;
        else pwm_set[i] = map(abs(motors[i]), 0, 100, 2, 255);

        digitalWrite(motordirectionPin[i], direction[i]); 
        analogWrite(motorpwmPin[i], pwm_set[i]); 
    }
}

/**
 * @brief Get distance reading from ultrasonic sensor
 */
float getUltrasonicDistance() {
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    
    long duration = pulseIn(echoPin, HIGH);
    float distance = duration * 0.034 / 2;  // Convert to centimeters
    
    return distance;
}

/**
 * @brief Control status LED
 */
void setStatusLED(bool state) {
    digitalWrite(ledPin, state);
}

2 Autonomous Navigation Algorithms (25 minutes)

Navigation Strategies:

  • Reactive Navigation: Respond to immediate sensor inputs
  • Behavior-Based: Combine multiple simple behaviors
  • State Machine: Different modes for different situations
  • Goal-Oriented: Navigate toward specific objectives
// Advanced navigation with state machine
enum NavigationState {
    EXPLORING,
    AVOIDING_OBSTACLE,
    FOLLOWING_WALL,
    SEARCHING,
    RETURNING_HOME
};

NavigationState currentState = EXPLORING;
unsigned long stateStartTime = 0;
int explorationDirection = 1;  // 1 = right, -1 = left

void autonomousNavigation() {
    float frontDistance = miniAuto.getDistance();
    unsigned long currentTime = millis();
    switch (currentState) {
        case EXPLORING:
            if (frontDistance < 20) {
                changeState(AVOIDING_OBSTACLE);
            } else {
                miniAuto.moveForward(180);
                miniAuto.setLED(GREEN);
                // Random direction changes
                if (currentTime - stateStartTime > 5000) {
                    if (random(0, 100) < 20) {  // 20% chance
                        changeState(SEARCHING);
                    }
                }
            }
            break;
        case AVOIDING_OBSTACLE:
            miniAuto.setLED(RED);
            miniAuto.stop();
            delay(300);
            // Turn away from obstacle
            if (explorationDirection > 0) {
                miniAuto.turnRight(150);
            } else {
                miniAuto.turnLeft(150);
            }
            delay(800);
            changeState(FOLLOWING_WALL);
            break;
        case FOLLOWING_WALL:
            miniAuto.setLED(YELLOW);
            // Follow wall for a while
            if (frontDistance > 40) {
                changeState(EXPLORING);
            } else {
                miniAuto.moveForward(120);
            }
            if (currentTime - stateStartTime > 3000) {
                changeState(EXPLORING);
            }
            break;
        case SEARCHING:
            miniAuto.setLED(BLUE);
            // Scanning behavior
            miniAuto.turnRight(100);
            if (currentTime - stateStartTime > 2000) {
                explorationDirection *= -1;  // Change direction
                changeState(EXPLORING);
            }
            break;
    }
}

void changeState(NavigationState newState) {
    currentState = newState;
    stateStartTime = millis();
    Serial.print("State changed to: ");
    Serial.println(newState);
}

3 Multi-Sensor Decision Making (15 minutes)

Sensor Fusion Concepts:

  • • Combine multiple sensor inputs for better decisions
  • • Handle conflicting sensor information
  • • Prioritize sensors based on reliability and context
  • • Create robust behaviors that work in various environments
// Multi-sensor decision making
struct SensorData {
    float distance;
    int lineSensorLeft;
    int lineSensorRight;
    float batteryVoltage;
    bool buttonPressed;
    unsigned long timestamp;
};

SensorData readAllSensors() {
    SensorData data;
    data.distance = miniAuto.getDistance();
    data.lineSensorLeft = miniAuto.getLineSensor(LEFT);
    data.lineSensorRight = miniAuto.getLineSensor(RIGHT);
    data.batteryVoltage = miniAuto.getBatteryVoltage();
    data.buttonPressed = miniAuto.isButtonPressed();
    data.timestamp = millis();
    return data;
}

void intelligentBehavior() {
    SensorData sensors = readAllSensors();
    // Priority 1: Safety (battery and obstacles)
    if (sensors.batteryVoltage < 6.5) {
        miniAuto.setLED(RED);
        miniAuto.playTone(880, 100);
        Serial.println("🔋 Low battery - returning to base");
        returnToBase();
        return;
    }
    // Priority 2: Emergency stop
    if (sensors.buttonPressed) {
        miniAuto.stop();
        miniAuto.setLED(RED);
        Serial.println("🛑 Emergency stop activated");
        while (miniAuto.isButtonPressed()) delay(100);
        return;
    }
    // Priority 3: Line following (if line detected)
    if (sensors.lineSensorLeft < 500 || sensors.lineSensorRight < 500) {
        followLine(sensors);
        return;
    }
    // Priority 4: Obstacle avoidance
    if (sensors.distance < 25) {
        avoidObstacle(sensors);
        return;
    }
    // Default: Explore
    miniAuto.moveForward(150);
    miniAuto.setLED(GREEN);
}

4 Debugging and Performance Optimization (15 minutes)

Debugging Techniques:

  • • Use Serial monitor for real-time debugging
  • • LED indicators for visual status feedback
  • • Sound cues for different robot states
  • • Systematic testing of individual components
// Debugging and monitoring system
                            bool debugMode = true;
                            unsigned long lastDebugOutput = 0;
                            
                            void debugOutput(String message, float value = -999) {
                                if (!debugMode) return;
                                Serial.print("[");
                                Serial.print(millis());
                                Serial.print("] ");
                                Serial.print(message);
                                if (value != -999) {
                                    Serial.print(": ");
                                    Serial.print(value);
                                }
                                Serial.println();
                            }
                            
                            void performanceMonitor() {
                                if (millis() - lastDebugOutput > 1000) {
                                    debugOutput("Distance", miniAuto.getDistance());
                                    debugOutput("Battery", miniAuto.getBatteryVoltage());
                                    debugOutput("State", currentState);
                                    debugOutput("Free RAM", ESP.getFreeHeap());
                                    lastDebugOutput = millis();
                                }
                            }
                            
                            // Performance optimization
                            void optimizedLoop() {
                                // Reduce sensor reading frequency
                                static unsigned long lastSensorRead = 0;
                                static float cachedDistance = 0;
                                if (millis() - lastSensorRead > 50) {  // 20Hz
                                    cachedDistance = miniAuto.getDistance();
                                    lastSensorRead = millis();
                                }
                                // Use cached value for decisions
                                makeDecision(cachedDistance);
                                // Monitor performance
                                performanceMonitor();
                            }

Hands-On Activity (25 minutes)

Project: Intelligent Explorer Robot

Students will create a sophisticated autonomous robot that demonstrates intelligent behavior using multiple sensors and decision-making algorithms.

Program Requirements:

  • • Implement state machine navigation
  • • Use multiple sensors for decision making
  • • Include safety features (battery monitoring, emergency stop)
  • • Add visual and audio feedback for different states
  • • Create debugging output for monitoring
  • • Optimize performance for smooth operation

Behavior Goals:

  • • Explore environment autonomously for 5+ minutes
  • • Avoid all obstacles without getting stuck
  • • Respond appropriately to different situations
  • • Provide clear status information to operator

Advanced Challenge:

Add a "learning" component where the robot remembers successful navigation strategies and adapts its behavior based on past experiences.

Assessment & Homework

Quick Check (In Class):

  • • Can student use miniAuto library functions effectively?
  • • Do they implement proper state machine logic?
  • • Are they integrating multiple sensors correctly?
  • • Can they debug and optimize their programs?

Homework Assignment:

Personal Robot Assistant

Create a robot that acts as a personal assistant - it can follow you around, respond to button presses with different behaviors, monitor your environment, and provide useful feedback through lights and sounds. Include at least 5 different "assistant modes".

← Previous: Lesson 13
📝 Take Lesson 14 Quiz Next: Lesson 15 →