← All projects

IEIndustrial Automation & EmbeddedDec 2022 – Mar 2023

Autonomous Guided Vehicle (AGV) for Industrial Material Handling

End-to-end AGV built for cost-effective, sustainable industrial use. A dynamic state machine (Active/Standby/Deep Sleep) plus MOSFET peripheral power gating and tuned PWM delivered a ~12% reduction in energy consumption while holding navigational performance.

  • Mechanical Design (CAD)
  • Embedded Control
  • Power Management
  • Sustainable Automation

Hardware & Architecture

  • High-fidelity CAD of chassis, drivetrain, and electronics enclosures for weight distribution, tolerance fits, and modular maintenance.
  • Robust MCU (STM32/ESP32) managing differential-drive kinematics, sensor polling, and state-machine execution.
  • MOSFET load switches gate power to non-essential sensors and high-draw motor drivers when idling.
  • PWM frequencies tuned to minimize switching losses during low-speed maneuvers.

Key Highlights

  • Dynamic state machine transitions the AGV between Active, Standby, and Deep Sleep based on task queues and sensor activity.
  • Peripheral power gating disconnects idle high-current loads via MOSFET switches.
  • Empirically validated ~12% reduction in energy consumption over a standard duty cycle.

Images

Code

agv_power_state_machine.inoPower-Management State Machinecpp
#include <Arduino.h>

// --- Hardware & Power Control Pins ---
const int motorEnablePin = 5; // PWM pin for motor speed control
const int motorDirPin1 = 6;
const int motorDirPin2 = 7;

// Power Gating MOSFETs
const int sensorPowerGate = 8; // Controls power to high-draw LiDAR/Sensors
const int motorPowerGate = 9;  // Controls main power to motor drivers

// --- System States ---
enum AGVState {
  STATE_NAVIGATING,
  STATE_STANDBY,
  STATE_LOW_POWER_SLEEP
};
AGVState currentState = STATE_STANDBY;
unsigned long lastActivityTime = 0;
const unsigned long SLEEP_TIMEOUT_MS = 30000; // 30 seconds of inactivity triggers sleep

void setup() {
  Serial.begin(115200);
  // Initialize Motor Control Pins
  pinMode(motorEnablePin, OUTPUT);
  pinMode(motorDirPin1, OUTPUT);
  pinMode(motorDirPin2, OUTPUT);
  // Initialize Power Gating Pins
  pinMode(sensorPowerGate, OUTPUT);
  pinMode(motorPowerGate, OUTPUT);
  // Power up system initially
  wakeUpSystem();
}

void loop() {
  checkTaskQueue();
  managePowerStates();

  // Execute state-specific behavior
  switch (currentState) {
    case STATE_NAVIGATING:
      executePathing();
      break;
    case STATE_STANDBY:
      // Awaiting tasks, full sensors active, motors stopped
      analogWrite(motorEnablePin, 0);
      break;
    case STATE_LOW_POWER_SLEEP:
      // Handled in state transition
      break;
  }
}

// --- Power Management Logic ---
void checkTaskQueue() {
  // Mock function: Check if there's an incoming command (e.g., via Serial or Wi-Fi)
  if (Serial.available() > 0) {
    char cmd = Serial.read();
    if (cmd == 'G') { // 'G' for Go/Task received
      lastActivityTime = millis();
      if (currentState == STATE_LOW_POWER_SLEEP) {
        wakeUpSystem();
      }
      currentState = STATE_NAVIGATING;
    } else if (cmd == 'S') { // 'S' for Stop
      currentState = STATE_STANDBY;
      lastActivityTime = millis();
    }
  }
}

void managePowerStates() {
  // If in standby for too long, transition to Low Power Mode to save ~12% baseline power
  if (currentState == STATE_STANDBY && (millis() - lastActivityTime > SLEEP_TIMEOUT_MS)) {
    Serial.println("[POWER_MGR] Inactivity timeout reached. Entering Low Power Mode.");
    enterLowPowerMode();
    currentState = STATE_LOW_POWER_SLEEP;
  }
}

void enterLowPowerMode() {
  // 1. Ensure motors are stopped securely
  analogWrite(motorEnablePin, 0);
  digitalWrite(motorDirPin1, LOW);
  digitalWrite(motorDirPin2, LOW);
  // 2. Gate power to high-draw peripherals (Active LOW MOSFETs assumed)
  digitalWrite(sensorPowerGate, HIGH); // Turn off sensors
  digitalWrite(motorPowerGate, HIGH);  // Disable motor driver power
  // 3. Lower CPU clock frequency (e.g., setCpuFrequencyMhz(80) on ESP32)
  Serial.println("[POWER_MGR] Peripherals gated. CPU throttled. System sleeping.");
}

void wakeUpSystem() {
  Serial.println("[POWER_MGR] Waking system. Restoring peripheral power.");
  // 1. Restore CPU frequency
  // 2. Restore power to peripherals
  digitalWrite(sensorPowerGate, LOW);
  digitalWrite(motorPowerGate, LOW);
  // Allow time for sensors (e.g., IMU, LiDAR) to boot and stabilize
  delay(500);
  currentState = STATE_STANDBY;
  lastActivityTime = millis();
}

void executePathing() {
  // Optimized Navigation Logic
  // e.g., using optimized PWM duty cycles rather than full power to reduce switching loss
  int optimizedPWM = 180; // Calculated efficient cruising speed
  digitalWrite(motorDirPin1, HIGH);
  digitalWrite(motorDirPin2, LOW);
  analogWrite(motorEnablePin, optimizedPWM);
  // Update activity timer while working
  lastActivityTime = millis();
}