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.
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();
}