0% found this document useful (0 votes)
3 views36 pages

ALR Code

The document outlines the code for an Autonomous Logistics Robot (ALR) using Arduino Mega 2560 with 8 QTR analog sensors for line tracking and obstacle avoidance. It details the configuration of sensor and motor pins, PD control constants, motor control functions, and obstacle detour logic, including timed movements to navigate around obstacles. The robot is designed to detect line loss and execute a detour while maintaining smooth tracking using a Proportional-Derivative controller.

Uploaded by

basharatmarwat69
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views36 pages

ALR Code

The document outlines the code for an Autonomous Logistics Robot (ALR) using Arduino Mega 2560 with 8 QTR analog sensors for line tracking and obstacle avoidance. It details the configuration of sensor and motor pins, PD control constants, motor control functions, and obstacle detour logic, including timed movements to navigate around obstacles. The robot is designed to detect line loss and execute a detour while maintaining smooth tracking using a Proportional-Derivative controller.

Uploaded by

basharatmarwat69
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Line tracking of ALR:

// ALR Line Tracking Code - Autonomous Logistics Robot


// Platform: Arduino Mega 2560 (C++) with 8x QTR Analog Sensors
and PD Control
//
// This code uses 8 analog QTR sensors to calculate a precise
line position (error)
// and applies a Proportional-Derivative (PD) controller for
smooth, fast tracking.
// The error range is -7000 (far left) to +7000 (far right), with
0 being perfectly centered.

// --- 1. CONFIGURATION: PIN DEFINITIONS ---

// Define QTR Sensor Pins (Analog Pins on Arduino Mega)


// Assuming QTR-8RC or similar module connected to Analog pins
const int QTR_PINS[8] = {A0, A1, A2, A3, A4, A5, A6, A7};
const int NUM_SENSORS = 8;

// Define Motor Driver Pins (2 x IBT-2 / BTS7960)


// IBT-2 requires PWM pin (RPWM/LPWM) and Enable pin (EN).
// We use the same PWM pin for forward/reverse control, setting
the other to LOW.
// Use Mega PWM pins (2-13, 44-46) for EN/PWM.
const int L_PWM = 3; // Left Motor PWM (RPWM/LPWM combined
logic)
const int L_EN = 38; // Left Motor Enable

const int R_PWM = 2; // Right Motor PWM (RPWM/LPWM combined


logic)
const int R_EN = 39; // Right Motor Enable

// Barcode Scanner (MC3000) - Assuming Serial connection


// We'll use Serial3 on the Mega for dedicated communication
(Pins 14 TX3, 15 RX3)
// For now, we will use the default Serial (pins 0, 1) for
simplicity and debugging.
const int BARCODE_SERIAL_PORT = 0; // Placeholder: Using default
Serial for reading

// Start Switch (Digital Input with Pullup)


const int START_SWITCH_PIN = 40; // Digital pin for the start
switch

// Lifting Mechanism Motor Pins (Assuming another IBT-2 or relay)


const int LIFT_PWM = 44; // PWM pin for lift speed control
const int LIFT_IN1 = 45; // Direction 1
const int LIFT_IN2 = 46; // Direction 2
// Define Motor Speeds (0-255)
const int BASE_SPEED = 180; // Base cruising speed (adjust for
24V motors)
const int MAX_SPEED = 255;
const int MIN_SPEED = 50; // Keep a minimum speed to prevent
stalling

// --- 2. PD CONTROL CONSTANTS ---


const float Kp = 0.08; // Proportional Gain: Must be tuned
carefully. Start small.
const float Kd = 0.05; // Derivative Gain: Start very small.

// --- 3. GLOBAL VARIABLES ---


float last_error = 0;
// Arrays to store calibration data for each sensor
int cal_min[NUM_SENSORS]; // Stores the minimum (darkest) reading
for each sensor
int cal_max[NUM_SENSORS]; // Stores the maximum (lightest)
reading for each sensor

// --- 4. MOTOR CONTROL FUNCTIONS ---

void set_motor_speeds(int left_pwm, int right_pwm) {


// IBT-2 requires the PWM pin to be driven high/low for
direction, and EN to be high.
digitalWrite(L_EN, HIGH);
digitalWrite(R_EN, HIGH);

// Note: IBT-2 drivers often use separate RPWM/LPWM.


// Assuming a simplified setup where we use one PWM pin and
rely on separate direction pins.
// For the actual IBT-2 (BTS7960), you should typically connect
L_PWM to LPWM and R_PWM to RPWM.
// The logic below assumes L_PWM/R_PWM are connected to the
main PWM input for speed.

// We ensure both motors are set to move FORWARD.


// For BTS7960, if RPWM=PWM and LPWM=0, it moves Forward (and
vice versa for reverse).
// The following is a simplified, common pin configuration for
IBT-2 with two PWM pins:
analogWrite(L_PWM, left_pwm);
analogWrite(R_PWM, right_pwm);
}

void stop_motors() {
digitalWrite(L_EN, LOW);
digitalWrite(R_EN, LOW);
analogWrite(L_PWM, 0);
analogWrite(R_PWM, 0);
}

void control_lifting_mechanism(int lift_speed, bool direction_up)


{
// Use a simple DC motor control for the lifting mechanism
analogWrite(LIFT_PWM, abs(lift_speed));
if (direction_up) {
digitalWrite(LIFT_IN1, HIGH);
digitalWrite(LIFT_IN2, LOW);
} else {
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, HIGH);
}
}

// --- 5. CALIBRATION FUNCTION ---

void calibrate_sensors() {
stop_motors();

[Link]("------------------------------------");
[Link]("CALIBRATION PHASE: 10 seconds");
[Link]("SLOWLY move the sensors over the line and
surface for 10s.");
[Link]("------------------------------------");

// Initialize min/max arrays


for (int i = 0; i < NUM_SENSORS; i++) {
cal_min[i] = 1023; // Start with max value
cal_max[i] = 0; // Start with min value
}

unsigned long startTime = millis();


while (millis() - startTime < 10000) { // Run for 10 seconds
for (int i = 0; i < NUM_SENSORS; i++) {
int reading = analogRead(QTR_PINS[i]);

// Update min/max values


if (reading < cal_min[i]) {
cal_min[i] = reading;
}
if (reading > cal_max[i]) {
cal_max[i] = reading;
}
}
delay(50); // Small delay to allow time for movement and
reading stability
}
[Link]("CALIBRATION COMPLETE. Readings:");
[Link]("Min (White): ");
for (int i = 0; i < NUM_SENSORS; i++)
[Link](String(cal_min[i]) + " ");
[Link]();
[Link]("Max (Black): ");
for (int i = 0; i < NUM_SENSORS; i++)
[Link](String(cal_max[i]) + " ");
[Link]("\n------------------------------------");
}

// --- 6. BARCODE SCANNER FUNCTION (Placeholder) ---

// Note: The MC3000 is a portable data collector and typically


sends data via
// a physical serial cable or wireless link. This is a simple
placeholder
// to read from the serial port where the barcode data might
arrive.
void check_barcode_scanner() {
if ([Link]() > 0) {
String barcode_data = [Link]('\n');
[Link]("BARCODE SCANNED: ");
[Link](barcode_data);
// TODO: Add logic here (e.g., stop robot, parse data, set
destination)
stop_motors();
// Example: control_lifting_mechanism(200, true); // Lift
cargo
delay(5000); // Wait for action
}
}

// --- 7. SETUP ---

void setup() {
// Motor Driver Pins
pinMode(L_PWM, OUTPUT);
pinMode(L_EN, OUTPUT);
pinMode(R_PWM, OUTPUT);
pinMode(R_EN, OUTPUT);

// Lifting Mechanism Pins


pinMode(LIFT_PWM, OUTPUT);
pinMode(LIFT_IN1, OUTPUT);
pinMode(LIFT_IN2, OUTPUT);

// Start Switch Pin (Internal pullup activated)


pinMode(START_SWITCH_PIN, INPUT_PULLUP);

// Sensor Pins are analog inputs by default, no need to set


pinMode.

[Link](9600);
[Link]("ALR Mega PD Line Tracker Initialized!");

// Perform calibration
calibrate_sensors();

// Wait for the start switch to be pressed (LOW signal when


pressed with PULLUP)
[Link]("WAITING FOR START SWITCH...");
while (digitalRead(START_SWITCH_PIN) == HIGH) {
// Wait until switch is pressed
delay(10);
}
[Link]("START SWITCH ACTIVATED. STARTING ROBOT.");
delay(1000); // Small delay after start to move hand
}

// --- 8. MAIN LOOP ---

void loop() {
// Always check for barcode data first, as it's a mission-
critical trigger
check_barcode_scanner();

// 1. READ & NORMALIZE SENSORS


// This calculates the line position as a single, smooth error
value.
long sum_weighted_values = 0; // The numerator for the weighted
average
long sum_raw_values = 0; // The denominator (total
reflectance)
float normalized_values[NUM_SENSORS];

for (int i = 0; i < NUM_SENSORS; i++) {


int raw_reading = analogRead(QTR_PINS[i]);

// Normalize reading (0 = White/Max Reflectance, 1 =


Black/Min Reflectance)
// Note: If max and min are the same (no range), set
normalized to 0.5 to avoid division by zero.
float range = (float)(cal_max[i] - cal_min[i]);
if (range == 0) range = 1;

// Calculate normalized value (0.0=White to 1.0=Black)


normalized_values[i] = constrain((raw_reading - cal_min[i]) /
range, 0.0, 1.0);

// Apply weights (e.g., -7000, -5000, -3000, -1000, 1000,


3000, 5000, 7000)
// Sensor index 0 is far left, index 7 is far right.
int position_weight = (i * 2000) - 7000; // Weights from -
7000 to +7000 (steps of 2000)

sum_weighted_values += (long)(normalized_values[i] *
position_weight);
sum_raw_values += (long)(normalized_values[i] * 1000); //
Scale up for precision
}

float error = 0;
if (sum_raw_values > 1000) { // Check if we are over the line
(ignore noise)
error = (float)sum_weighted_values / sum_raw_values;
} else {
// If we lose the line, stop or search
stop_motors();
[Link]("Action: STOP (Lost line)");
last_error = 0;
return;
}

// 2. CALCULATE PD CORRECTION

// P-Term (Proportional):
float P_term = Kp * error;

// D-Term (Derivative):
float derivative = error - last_error;
float D_term = Kd * derivative;

// Total Correction
float motor_correction = P_term + D_term;

// 3. APPLY CORRECTION TO MOTORS


// Correction slows down the wheel on the side the line is on
(i.e., reduces turning)

int left_speed = BASE_SPEED - (int)motor_correction;


int right_speed = BASE_SPEED + (int)motor_correction;

// 4. CONSTRAIN SPEEDS
left_speed = constrain(left_speed, MIN_SPEED, MAX_SPEED);
right_speed = constrain(right_speed, MIN_SPEED, MAX_SPEED);
// 5. EXECUTE MOVEMENT
set_motor_speeds(left_speed, right_speed);

// 6. STORE CURRENT ERROR


last_error = error;

// 7. DEBUGGING OUTPUT
[Link]("Error: ");
[Link](error);
[Link](" | L Speed: ");
[Link](left_speed);
[Link](" | R Speed: ");
[Link](right_speed);
}
LIne following with obstacle avoiding :
// ALR Line Tracking Code - Autonomous Logistics Robot
// Platform: Arduino Mega 2560 (C++) with 8x QTR Analog Sensors,
PD Control,
// and Obstacle Detour Logic (No Extra Sensors, based on video
and rules)
//
// The robot detects an obstacle when the line is abruptly lost
(all sensors read white).
// It then executes a fixed, timed detour to bypass the obstacle
and re-acquire the line.

// --- 1. CONFIGURATION: PIN DEFINITIONS ---

// Line Sensor Pins (Analog Pins)


const int QTR_PINS[8] = {A0, A1, A2, A3, A4, A5, A6, A7};
const int NUM_SENSORS = 8;

// Motor Driver Pins (2 x IBT-2 / BTS7960)


const int L_PWM = 3; // Left Motor PWM
const int L_EN = 38; // Left Motor Enable
const int R_PWM = 2; // Right Motor PWM
const int R_EN = 39; // Right Motor Enable

// Barcode Scanner & Switch Pins


// Assuming a camera module or similar QR/Barcode reader that
communicates over Serial
const int START_SWITCH_PIN = 40; // Digital pin for the start
switch

// Lifting Mechanism Motor Pins (Placeholder structure)


const int LIFT_PWM = 44;
const int LIFT_IN1 = 45;
const int LIFT_IN2 = 46;
// Define Motor Speeds (0-255)
const int BASE_SPEED = 180;
const int MAX_SPEED = 255;
const int MIN_SPEED = 50;
const int DETOUR_SPEED = 150; // Slower speed for controlled
detour

// --- 2. OBSTACLE DETOUR CONFIGURATION ---


// These timing values must be tuned based on your robot's size
and speed.
// Assuming the robot detours left to go around the obstacle.
const int DETOUR_TURN_TIME_MS = 300; // Time for the 90-degree
turn
const int DETOUR_FORWARD_TIME_MS = 1500; // Time to drive past
the obstacle
const int DETOUR_RE_ACQUIRE_TURN_MS = 600; // Time to turn back
and search for the line

// Threshold to detect line loss (all sensors reading


white/light)
const long LINE_LOST_THRESHOLD = 800; // If total normalized
reading (0-8000) is below this, the line is lost.

// --- 3. PD CONTROL CONSTANTS ---


const float Kp = 0.08;
const float Kd = 0.05;

// --- 4. GLOBAL VARIABLES ---


float last_error = 0;
int cal_min[NUM_SENSORS];
int cal_max[NUM_SENSORS];
bool is_avoiding = false; // State flag for the avoidance
sequence

// --- 5. MOTOR CONTROL FUNCTIONS ---

void set_motor_speeds(int left_pwm, int right_pwm) {


digitalWrite(L_EN, HIGH);
digitalWrite(R_EN, HIGH);
analogWrite(L_PWM, left_pwm);
analogWrite(R_PWM, right_pwm);
}

void stop_motors() {
digitalWrite(L_EN, LOW);
digitalWrite(R_EN, LOW);
analogWrite(L_PWM, 0);
analogWrite(R_PWM, 0);
}
void turn_robot(int duration_ms, int left_speed, int right_speed)
{
// Utility function to execute a timed movement
set_motor_speeds(left_speed, right_speed);
delay(duration_ms);
stop_motors();
}

void control_lifting_mechanism(int lift_speed, bool direction_up)


{
// Placeholder: control for the lift motor
analogWrite(LIFT_PWM, abs(lift_speed));
if (direction_up) {
digitalWrite(LIFT_IN1, HIGH);
digitalWrite(LIFT_IN2, LOW);
} else {
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, HIGH);
}
}

// --- 6. SENSOR AND CALIBRATION FUNCTIONS ---

void calibrate_sensors() {
stop_motors();
[Link]("------------------------------------");
[Link]("CALIBRATION PHASE: 10 seconds");
[Link]("SLOWLY move the sensors over the line and
surface for 10s.");
[Link]("------------------------------------");

for (int i = 0; i < NUM_SENSORS; i++) {


cal_min[i] = 1023;
cal_max[i] = 0;
}

unsigned long startTime = millis();


while (millis() - startTime < 10000) {
for (int i = 0; i < NUM_SENSORS; i++) {
int reading = analogRead(QTR_PINS[i]);
if (reading < cal_min[i]) cal_min[i] = reading;
if (reading > cal_max[i]) cal_max[i] = reading;
}
delay(50);
}

[Link]("CALIBRATION COMPLETE.");
[Link]("------------------------------------");
}
// --- 7. BARCODE SCANNER FUNCTION (Placeholder) ---

void check_barcode_scanner() {
// This uses the Arduino's primary Serial port for
demonstration.
// In a real robot, this would be a separate Serial port (e.g.,
Serial1 on Mega)
// connected to the QR code reader/camera module.
if ([Link]() > 0) {
String barcode_data = [Link]('\n');
[Link]("BARCODE SCANNED: ");
[Link](barcode_data);
stop_motors();
// Action: Read command, perform pickup/dropoff sequence
(e.g., Lift cargo)
// control_lifting_mechanism(200, true);
delay(5000);
// Clear buffer after action
while([Link]() > 0) [Link]();
}
}

// --- 8. OBSTACLE DETOUR LOGIC ---

void execute_detour() {
[Link]("!!! LINE LOST / OBSTACLE DETECTED. STARTING
DETOUR SEQUENCE !!!");
is_avoiding = true;
stop_motors();
delay(500);

// STEP 1: Turn Left (90 degrees, to move parallel to the


obstacle)
// Robot pivots left (Left wheel reverse/stop, Right wheel
forward)
[Link]("Detour Step 1: Turning Left...");
turn_robot(DETOUR_TURN_TIME_MS, -DETOUR_SPEED, DETOUR_SPEED);

// STEP 2: Move Forward (To drive past the obstacle)


[Link]("Detour Step 2: Moving Forward...");
turn_robot(DETOUR_FORWARD_TIME_MS, DETOUR_SPEED, DETOUR_SPEED);

// STEP 3: Turn Right (90+ degrees, to turn back and search for
the line)
// Robot pivots right (Left wheel forward, Right wheel
reverse/stop)
[Link]("Detour Step 3: Turning Right to Re-acquire
Line...");
turn_robot(DETOUR_RE_ACQUIRE_TURN_MS, DETOUR_SPEED, -
DETOUR_SPEED);

is_avoiding = false;
[Link]("!!! DETOUR COMPLETE. RESUMING LINE
TRACKING. !!!");
last_error = 0; // Reset error after detour
}

// --- 9. SETUP ---

void setup() {
// Configure Motor Pins
pinMode(L_PWM, OUTPUT); pinMode(L_EN, OUTPUT);
pinMode(R_PWM, OUTPUT); pinMode(R_EN, OUTPUT);

// Configure Lifting Mechanism Pins


pinMode(LIFT_PWM, OUTPUT);
pinMode(LIFT_IN1, OUTPUT);
pinMode(LIFT_IN2, OUTPUT);

// Configure Start Switch Pin


pinMode(START_SWITCH_PIN, INPUT_PULLUP);

[Link](9600);
[Link]("ALR Mega PD Line Tracker with Detour Logic
Initialized!");

// Perform calibration
calibrate_sensors();

// Wait for the start switch


[Link]("WAITING FOR START SWITCH...");
while (digitalRead(START_SWITCH_PIN) == HIGH) {
delay(10);
}
[Link]("START SWITCH ACTIVATED. STARTING ROBOT.");
delay(1000);
}

// --- 10. MAIN LOOP ---

void loop() {
// 1. CRITICAL CHECK: BARCODE SCANNER
check_barcode_scanner();

// 2. READ & NORMALIZE SENSORS


long sum_weighted_values = 0;
long sum_normalized_values = 0; // Sum of normalized values (0
to 8000)
float normalized_values[NUM_SENSORS];
bool on_line = false;

for (int i = 0; i < NUM_SENSORS; i++) {


int raw_reading = analogRead(QTR_PINS[i]);

float range = (float)(cal_max[i] - cal_min[i]);


if (range == 0) range = 1;

// Calculate normalized value (0.0=White to 1.0=Black)


// Scaling this by 1000 for easier thresholding/math later
normalized_values[i] = constrain((raw_reading - cal_min[i]) /
range, 0.0, 1.0);

// Check if at least one sensor sees black (i.e., we are


still on the line)
if (normalized_values[i] > 0.5) on_line = true;

// Apply weights (-7000 to +7000)


int position_weight = (i * 2000) - 7000;

sum_weighted_values += (long)(normalized_values[i] *
position_weight);
sum_normalized_values += (long)(normalized_values[i] * 1000);
}

// 3. OBSTACLE/LINE LOSS DETECTION


// If the sum of normalized values is very low, the line has
been lost or interrupted by an obstacle.
if (sum_normalized_values < LINE_LOST_THRESHOLD && !
is_avoiding) {
execute_detour();
return; // Start the loop over after detour
}

// 4. LINE FOLLOWING LOGIC (Only runs if not currently


avoiding)
if (!is_avoiding) {
float error = 0;

if (sum_normalized_values > 0) {
error = (float)sum_weighted_values / sum_normalized_values;
} else {
// Emergency stop if line is completely lost (should be
caught by the Detour logic above,
// but this acts as a final fail-safe for line loss)
stop_motors();
[Link]("Action: Emergency STOP (Complete line
loss)");
last_error = 0;
return;
}

// CALCULATE PD CORRECTION
float P_term = Kp * error;
float derivative = error - last_error;
float D_term = Kd * derivative;
float motor_correction = P_term + D_term;

// APPLY CORRECTION TO MOTORS


int left_speed = BASE_SPEED - (int)motor_correction;
int right_speed = BASE_SPEED + (int)motor_correction;

// CONSTRAIN SPEEDS
left_speed = constrain(left_speed, MIN_SPEED, MAX_SPEED);
right_speed = constrain(right_speed, MIN_SPEED, MAX_SPEED);

// EXECUTE MOVEMENT
set_motor_speeds(left_speed, right_speed);

// STORE CURRENT ERROR


last_error = error;

// DEBUGGING OUTPUT
[Link]("Error: ");
[Link](error);
[Link](" | L Speed: ");
[Link](left_speed);
[Link](" | R Speed: ");
[Link](right_speed);
}
}

Barcode scanning and


lifting and dropping load:
// ALR Logistics Task Handler - Autonomous Logistics Robot
// Platform: Arduino Mega 2560 (C++)
//
// This code focuses on the QR code scanning and the controlled
lifting/dropping
// sequence required for the Autonomous Logistics Robot (ALR)
competition.
// It uses a simple state machine to manage the robot's action
flow.
// This is designed to be integrated into a larger line-following
program.

// --- 1. CONFIGURATION: PIN DEFINITIONS ---

// Motor Driver Pins (Required for stopping during task)


const int L_PWM = 3; // Left Motor PWM
const int L_EN = 38; // Left Motor Enable
const int R_PWM = 2; // Right Motor PWM
const int R_EN = 39; // Right Motor Enable

// Lifting Mechanism Motor Pins (DC Motor control assumed)


const int LIFT_PWM = 44; // PWM for speed control
const int LIFT_IN1 = 45; // Direction Input 1
const int LIFT_IN2 = 46; // Direction Input 2

// Barcode/QR Code Scanner Serial Port


// The Mega has multiple hardware serial ports. Serial1 is often
used for a dedicated
// scanner module (like a camera or TTL scanner).
#define QR_SERIAL Serial1

// Start Switch Pin


const int START_SWITCH_PIN = 40;

// --- 2. LIFTING MECHANISM CONSTANTS ---


const int LIFT_SPEED = 200; // Speed of the lift motor (0-255)
const int LIFT_DURATION_MS = 2500; // Time required to fully lift
or drop the weight

// --- 3. ROBOT STATE MANAGEMENT ---

enum RobotState {
STATE_IDLE, // Waiting for start switch
STATE_LINE_FOLLOWING, // Following the track
STATE_PERFORMING_TASK // Stopped to lift or drop cargo
};

RobotState current_state = STATE_IDLE;


bool has_cargo = false; // Flag to track if the robot is
currently carrying a load

// --- 4. MOTOR AND LIFT CONTROL FUNCTIONS ---

void set_motor_speeds(int left_pwm, int right_pwm) {


// Simple motor control to stop the robot
digitalWrite(L_EN, HIGH);
digitalWrite(R_EN, HIGH);
analogWrite(L_PWM, left_pwm);
analogWrite(R_PWM, right_pwm);
}

void stop_motors() {
set_motor_speeds(0, 0);
digitalWrite(L_EN, LOW);
digitalWrite(R_EN, LOW);
}

void control_lifting_mechanism(bool lift_up) {


// Commands the lift motor to move up or down for a fixed
duration.
[Link](lift_up ? "LIFTING CARGO..." : "DROPPING
CARGO...");

// Set direction
if (lift_up) {
// Lift UP (e.g., IN1=HIGH, IN2=LOW)
digitalWrite(LIFT_IN1, HIGH);
digitalWrite(LIFT_IN2, LOW);
} else {
// Drop DOWN (e.g., IN1=LOW, IN2=HIGH)
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, HIGH);
}

// Set speed
analogWrite(LIFT_PWM, LIFT_SPEED);

// Run for duration


delay(LIFT_DURATION_MS);

// Stop the motor and remove power


analogWrite(LIFT_PWM, 0);
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, LOW); // Important to prevent
braking/heating

if (lift_up) {
has_cargo = true;
[Link]("CARGO LIFTED. STATUS: Loaded.");
} else {
has_cargo = false;
[Link]("CARGO DROPPED. STATUS: Empty.");
}
}

// --- 5. LOGISTICS TASK HANDLER ---


void handle_logistics_task(String qr_command) {
// Task Logic: Scan QR and decide to Pick up or Drop off

// Example QR commands:
// 'P' -> Pickup (Lift)
// 'D' -> Dropoff (Drop)

// 1. Stop the line following process


current_state = STATE_PERFORMING_TASK;
stop_motors();
[Link]("QR Code Scanned: ");
[Link](qr_command);

// Give a moment for the robot to settle


delay(1000);

if (qr_command.startsWith("P")) {
// Pickup instruction received
if (!has_cargo) {
control_lifting_mechanism(true); // true = lift up
} else {
[Link]("Already carrying cargo, skipping pickup.");
}
}
else if (qr_command.startsWith("D")) {
// Drop-off instruction received
if (has_cargo) {
control_lifting_mechanism(false); // false = drop down
} else {
[Link]("No cargo to drop, skipping drop-off.");
}
}
else {
[Link]("Unknown QR command or location. Task
skipped.");
}

// 2. Return to line following


current_state = STATE_LINE_FOLLOWING;
[Link]("Resuming line following.");
}

// --- 6. MAIN SERIAL SCANNER LOOP ---

void check_qr_scanner() {
if (QR_SERIAL.available() > 0) {
// Read the data sent by the QR scanner
String data = QR_SERIAL.readStringUntil('\n');
[Link](); // Remove any whitespace

// Process the command


handle_logistics_task(data);

// Clear buffer after action


while(QR_SERIAL.available() > 0) QR_SERIAL.read();
}
}

// --- 7. SETUP ---

void setup() {
// Initialize Serial ports
[Link](9600); // PC communication
QR_SERIAL.begin(9600); // QR Scanner communication (adjust baud
rate if needed)
[Link]("ALR Logistics Handler Initialized!");

// Configure Motor Pins


pinMode(L_PWM, OUTPUT); pinMode(L_EN, OUTPUT);
pinMode(R_PWM, OUTPUT); pinMode(R_EN, OUTPUT);

// Configure Lifting Mechanism Pins


pinMode(LIFT_PWM, OUTPUT);
pinMode(LIFT_IN1, OUTPUT);
pinMode(LIFT_IN2, OUTPUT);

// Initialize lift to neutral/stop state


analogWrite(LIFT_PWM, 0);
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, LOW);

// Configure Start Switch Pin


pinMode(START_SWITCH_PIN, INPUT_PULLUP);

// Wait for the start switch


[Link]("WAITING FOR START SWITCH...");
stop_motors();
while (digitalRead(START_SWITCH_PIN) == HIGH) {
delay(10);
}
current_state = STATE_LINE_FOLLOWING;
[Link]("START SWITCH ACTIVATED. Entering Line Following
State.");
delay(1000);
}

// --- 8. MAIN LOOP ---


void loop() {
// Always check the QR scanner regardless of the current state
// as the line following portion (which you'll integrate here)
// should keep running until the scanner signals a task.
check_qr_scanner();

// The line following code from the previous file would go


here:
// if (current_state == STATE_LINE_FOLLOWING) {
// // ... PD control logic and motor commands ...
// // Example: set_motor_speeds(BASE_SPEED, BASE_SPEED);
// }

// Since this code is only for the task handling, we will


simulate
// the 'Line Following' state with a simple forward movement.
if (current_state == STATE_LINE_FOLLOWING) {
set_motor_speeds(150, 150); // Just move forward slowly for
simulation
} else if (current_state == STATE_IDLE) {
stop_motors();
}
}

Master
Code
// ALR Competition Master Code - TIF'25 Autonomous Logistics
Robot
// Platform: Arduino Mega 2560 (C++)
// Includes PD Line Tracking, Obstacle Detour, and QR Code
Logistics Handling.

// --- 1. CONFIGURATION: PIN DEFINITIONS ---

// Line Sensor Pins (Analog Pins: QTR Array)


const int QTR_PINS[8] = {A0, A1, A2, A3, A4, A5, A6, A7};
const int NUM_SENSORS = 8;

// Motor Driver Pins (Drive Motors: 2 x IBT-2 / BTS7960 or


similar)
// Use hardware PWM pins for smoother control (2, 3 are used
here)
const int L_PWM = 3; // Left Motor PWM Speed
const int L_DIR = 38; // Left Motor Direction/Enable (using as
Direction)
const int R_PWM = 2; // Right Motor PWM Speed
const int R_DIR = 39; // Right Motor Direction/Enable (using as
Direction)

// Lifting Mechanism Motor Pins (DC Motor control assumed via


L298N or similar)
const int LIFT_PWM = 44; // PWM for speed control
const int LIFT_IN1 = 45; // Direction Input 1
const int LIFT_IN2 = 46; // Direction Input 2

// Start/Stop & Scanner Configuration


const int START_SWITCH_PIN = 40; // Digital pin for the start
switch
#define QR_SERIAL Serial1 // Use Serial1 (Mega Pins
19/18) for the QR Scanner

// --- 2. SPEED, CONTROL, AND TIMING CONSTANTS ---

// Line Following Speeds (Adjust these)


const int BASE_SPEED = 180; // Base PWM speed (0-255)
const int MAX_SPEED = 255; // Maximum speed limit
const int MIN_SPEED = 50; // Minimum speed limit

// PD Control Constants (Critical for performance, must be tuned


on the track)
const float Kp = 0.08;
const float Kd = 0.05;

// Obstacle Detour Configuration (Crucial Timings for bypass)


const int DETOUR_SPEED = 160;
const int DETOUR_TURN_TIME_MS = 350; // Time for initial turn
(e.g., 90 degrees left)
const int DETOUR_FORWARD_TIME_MS = 1600; // Time to drive past
the obstacle
const int DETOUR_RE_ACQUIRE_TURN_MS = 700; // Time to turn back
(90+ degrees right)

// Line Loss Threshold (0-8000 scale: 8 sensors * 1000 max


normalized value)
// If the sum of normalized values is below this, the line is
considered lost/interrupted.
const long LINE_LOST_THRESHOLD = 800;

// Lifting Mechanism Constants


const int LIFT_SPEED = 200; // Speed of the lift motor
const int LIFT_DURATION_MS = 2500; // Time to fully lift or drop
the weight
// --- 3. GLOBAL STATE VARIABLES ---

enum RobotState {
STATE_IDLE, // Waiting for start
STATE_LINE_FOLLOWING, // Normal operation
STATE_PERFORMING_TASK, // Stopped for Pickup/Drop-off
STATE_AVOIDING_OBSTACLE // Executing the timed detour
};

RobotState current_state = STATE_IDLE;


float last_error = 0;
bool has_cargo = false; // Tracks if the robot is currently
carrying a load

// Sensor Calibration Arrays


int cal_min[NUM_SENSORS];
int cal_max[NUM_SENSORS];

// --- 4. MOTOR CONTROL FUNCTIONS ---

/**
* @brief Sets the speed and direction for both drive motors.
* @param left_pwm PWM value for the left motor (-255 to 255).
Negative means reverse.
* @param right_pwm PWM value for the right motor (-255 to 255).
Negative means reverse.
*/
void set_motor_speeds(int left_pwm, int right_pwm) {
// Left Motor Direction
digitalWrite(L_DIR, left_pwm >= 0 ? HIGH : LOW);
analogWrite(L_PWM, abs(left_pwm));

// Right Motor Direction


digitalWrite(R_DIR, right_pwm >= 0 ? HIGH : LOW);
analogWrite(R_PWM, abs(right_pwm));
}

void stop_motors() {
set_motor_speeds(0, 0);
}

/**
* @brief Executes a timed movement (e.g., for detours or
specific maneuvers).
*/
void turn_robot(int duration_ms, int left_speed, int right_speed)
{
set_motor_speeds(left_speed, right_speed);
delay(duration_ms);
stop_motors();
}

/**
* @brief Controls the lifting mechanism motor.
* @param lift_up true to lift cargo (up), false to drop cargo
(down).
*/
void control_lifting_mechanism(bool lift_up) {
[Link](lift_up ? "LIFTING CARGO..." : "DROPPING
CARGO...");

// Set direction
if (lift_up) {
digitalWrite(LIFT_IN1, HIGH);
digitalWrite(LIFT_IN2, LOW);
} else {
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, HIGH);
}

// Set speed and run for duration


analogWrite(LIFT_PWM, LIFT_SPEED);
delay(LIFT_DURATION_MS);

// Stop the motor


analogWrite(LIFT_PWM, 0);
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, LOW);

if (lift_up) {
has_cargo = true;
[Link]("CARGO LIFTED. STATUS: Loaded.");
} else {
has_cargo = false;
[Link]("CARGO DROPPED. STATUS: Empty.");
}
}

// --- 5. CALIBRATION AND SENSOR PROCESSING ---

void calibrate_sensors() {
stop_motors();
[Link]("--- CALIBRATION PHASE (10 seconds) ---");
[Link]("Move sensors over black line and white
surface.");

for (int i = 0; i < NUM_SENSORS; i++) {


cal_min[i] = 1023;
cal_max[i] = 0;
}

unsigned long startTime = millis();


while (millis() - startTime < 10000) {
for (int i = 0; i < NUM_SENSORS; i++) {
int reading = analogRead(QTR_PINS[i]);
if (reading < cal_min[i]) cal_min[i] = reading;
if (reading > cal_max[i]) cal_max[i] = reading;
}
delay(50);
}

[Link]("CALIBRATION COMPLETE. Starting run in 2


seconds.");
delay(2000);
}

/**
* @brief Calculates the weighted position error from the line
sensors.
* @return float The error value (e.g., -7000 to +7000).
*/
float read_line_sensors() {
long sum_weighted_values = 0;
long sum_normalized_values = 0;

for (int i = 0; i < NUM_SENSORS; i++) {


int raw_reading = analogRead(QTR_PINS[i]);

// Normalize reading (0.0 = White to 1.0 = Black)


float range = (float)(cal_max[i] - cal_min[i]);
if (range < 50) range = 50; // Safety against poor
calibration

float normalized_value = constrain((raw_reading - cal_min[i])


/ range, 0.0, 1.0);

// Apply weights: Sensor 0 = -7000, Sensor 7 = +7000


(Increments of 2000)
int position_weight = (i * 2000) - 7000;

sum_weighted_values += (long)(normalized_value *
position_weight);
sum_normalized_values += (long)(normalized_value * 1000); //
Sum on a 0-8000 scale
}

// Check for line loss (used to detect obstacles)


if (sum_normalized_values < LINE_LOST_THRESHOLD) {
// Line lost, switch state to avoidance
if (current_state == STATE_LINE_FOLLOWING) {
current_state = STATE_AVOIDING_OBSTACLE;
}
return 0; // Return zero error while avoiding
}

// Calculate error only if sum_normalized_values is positive


(i.e., we are on the line)
if (sum_normalized_values > 0) {
// Error is a value from -7 to +7 (scaled from the -7000 to
+7000 range)
return (float)sum_weighted_values / sum_normalized_values;
} else {
// Should not happen if threshold check works, but as a
fail-safe
return last_error;
}
}

// --- 6. OBSTACLE AVOIDANCE LOGIC ---

void execute_detour() {
[Link]("!!! LINE LOST / OBSTACLE DETECTED. STARTING
DETOUR SEQUENCE !!!");
stop_motors();
delay(500);

// STEP 1: Turn Left (to move parallel to the obstacle)


// Turn left (Left motor reverse, Right motor forward)
[Link]("Detour Step 1: Turning Left...");
turn_robot(DETOUR_TURN_TIME_MS, -DETOUR_SPEED, DETOUR_SPEED);

// STEP 2: Move Forward (To drive past the obstacle)


[Link]("Detour Step 2: Moving Forward...");
turn_robot(DETOUR_FORWARD_TIME_MS, DETOUR_SPEED, DETOUR_SPEED);

// STEP 3: Turn Right (to turn back and search for the line)
// Turn right (Left motor forward, Right motor reverse)
[Link]("Detour Step 3: Turning Right to Re-acquire
Line...");
turn_robot(DETOUR_RE_ACQUIRE_TURN_MS, DETOUR_SPEED, -
DETOUR_SPEED);

// Revert state back to line following


current_state = STATE_LINE_FOLLOWING;
last_error = 0; // Reset error to prevent immediate over-
correction
[Link]("!!! DETOUR COMPLETE. RESUMING LINE
TRACKING. !!!");
}

// --- 7. LOGISTICS TASK HANDLER (QR Code) ---

void handle_logistics_task(String qr_command) {


// Task Logic: Scan QR and decide to Pick up or Drop off

current_state = STATE_PERFORMING_TASK;
stop_motors();
[Link]("QR Code Scanned: ");
[Link](qr_command);

delay(500); // Pause for stability

if (qr_command.startsWith("P")) {
// Pickup instruction received
if (!has_cargo) {
control_lifting_mechanism(true); // true = lift up
} else {
[Link]("Already carrying cargo, skipping pickup.");
}
}
else if (qr_command.startsWith("D")) {
// Drop-off instruction received
if (has_cargo) {
control_lifting_mechanism(false); // false = drop down
} else {
[Link]("No cargo to drop, skipping drop-off.");
}
}
else {
[Link]("Unknown QR command. Task skipped.");
}

// Resume line following


current_state = STATE_LINE_FOLLOWING;
[Link]("Resuming line following.");
}

void check_qr_scanner() {
// Only check the scanner if the robot is currently moving
(following line or idling before start)
if (QR_SERIAL.available() > 0) {
// Read the data sent by the QR scanner
String data = QR_SERIAL.readStringUntil('\n');
[Link](); // Remove any whitespace
// Only handle task if a valid command is received
if ([Link]("P") || [Link]("D")) {
handle_logistics_task(data);
}

// Clear buffer after action


while(QR_SERIAL.available() > 0) QR_SERIAL.read();
}
}

// --- 8. ARDUINO SETUP ---

void setup() {
// Initialize Communication
[Link](9600); // PC Serial Monitor
QR_SERIAL.begin(9600); // QR Scanner (Make sure the scanner
baud rate matches)
[Link]("ALR Master Program Initialized.");

// Configure Drive Motor Pins


pinMode(L_PWM, OUTPUT); pinMode(L_DIR, OUTPUT);
pinMode(R_PWM, OUTPUT); pinMode(R_DIR, OUTPUT);

// Configure Lifting Mechanism Pins


pinMode(LIFT_PWM, OUTPUT);
pinMode(LIFT_IN1, OUTPUT);
pinMode(LIFT_IN2, OUTPUT);

// Configure Start Switch Pin


pinMode(START_SWITCH_PIN, INPUT_PULLUP);

// Perform sensor calibration


calibrate_sensors();

// Wait for the start switch


[Link]("WAITING FOR START SWITCH...");
stop_motors();
while (digitalRead(START_SWITCH_PIN) == HIGH) {
delay(10);
}

current_state = STATE_LINE_FOLLOWING;
[Link]("START SWITCH ACTIVATED. Entering Line Following
State.");
delay(1000);
}

// --- 9. ARDUINO MAIN LOOP ---


void loop() {
// High-priority check: Always monitor for QR code to interrupt
movement
check_qr_scanner();

switch (current_state) {

case STATE_LINE_FOLLOWING: {
float error = read_line_sensors(); // This function may
change the state to AVOIDING_OBSTACLE

// If the state was changed to AVOIDING, break and let the


next case handle it
if (current_state == STATE_AVOIDING_OBSTACLE) {
break; +0.
}

// Calculate PD CORRECTION
float P_term = Kp * error;
float derivative = error - last_error;
float D_term = Kd * derivative;
float motor_correction = P_term + D_term;

// Apply Correction to Motors


int left_speed = BASE_SPEED - (int)motor_correction;
int right_speed = BASE_SPEED + (int)motor_correction;

// Constrain Speeds to prevent maxing out too often or


going too slow
left_speed = constrain(left_speed, MIN_SPEED, MAX_SPEED);
right_speed = constrain(right_speed, MIN_SPEED, MAX_SPEED);

// Execute Movement
set_motor_speeds(left_speed, right_speed);

// Store Current Error


last_error = error;

// Optional: Serial Debugging (Comment out for fastest


performance)
// [Link]("Error: "); [Link](error);
// [Link](" | L Speed: "); [Link](left_speed);
// [Link](" | R Speed: ");
[Link](right_speed);
break;
}

case STATE_AVOIDING_OBSTACLE: {
// Execute detour maneuver once, then revert to
LINE_FOLLOWING
execute_detour();
break;
}

case STATE_PERFORMING_TASK:
// The task handler already stops the motors and handles
the lift sequence.
// We do nothing here, just wait for the state to be
changed back to LINE_FOLLOWING
// by the handle_logistics_task function.
stop_motors();
break;

case STATE_IDLE:
// Should only happen before the start switch is pressed
stop_motors();
break;
}
}

2nd finalized by deepseek:


// ALR Competition Master Code - TIF'25 Autonomous
Logistics Robot
// Platform: Arduino Mega 2560 (C++)
// Includes PD Line Tracking, Obstacle Detour, and QR Code
Logistics Handling.

// --- 1. CONFIGURATION: PIN DEFINITIONS ---

// Line Sensor Pins (Analog Pins: QTR Array)


const int QTR_PINS[8] = {A0, A1, A2, A3, A4, A5, A6, A7};
const int NUM_SENSORS = 8;

// Motor Driver Pins (Drive Motors: 2 x IBT-2 / BTS7960 or


similar)
const int L_PWM = 3; // Left Motor PWM Speed
const int L_DIR = 38; // Left Motor Direction/Enable
const int R_PWM = 2; // Right Motor PWM Speed
const int R_DIR = 39; // Right Motor Direction/Enable

// Lifting Mechanism Motor Pins


const int LIFT_PWM = 44; // PWM for speed control
const int LIFT_IN1 = 45; // Direction Input 1
const int LIFT_IN2 = 46; // Direction Input 2
// Start/Stop & Scanner Configuration
const int START_SWITCH_PIN = 40; // Digital pin for the start
switch
#define QR_SERIAL Serial1 // Use Serial1 (Mega Pins
19/18) for the QR Scanner

// --- 2. SPEED, CONTROL, AND TIMING CONSTANTS ---

// Line Following Speeds (Adjust these)


const int BASE_SPEED = 180; // Base PWM speed (0-255)
const int MAX_SPEED = 255; // Maximum speed limit
const int MIN_SPEED = 50; // Minimum speed limit

// PD Control Constants
const float Kp = 0.08;
const float Kd = 0.05;

// Obstacle Detour Configuration


const int DETOUR_SPEED = 160;
const int DETOUR_TURN_TIME_MS = 350; // Time for initial
turn
const int DETOUR_FORWARD_TIME_MS = 1600; // Time to
drive past obstacle
const int DETOUR_RE_ACQUIRE_TURN_MS = 700; // Time to
turn back

// Line Loss Threshold - FIXED: Increased threshold for better


detection
const long LINE_LOST_THRESHOLD = 2000; // Increased from
800

// Lifting Mechanism Constants


const int LIFT_SPEED = 200; // Speed of the lift motor
const int LIFT_DURATION_MS = 2500; // Time to fully lift or
drop

// --- 3. GLOBAL STATE VARIABLES ---

enum RobotState {
STATE_IDLE, // Waiting for start
STATE_LINE_FOLLOWING, // Normal operation
STATE_PERFORMING_TASK, // Stopped for Pickup/Drop-off
STATE_AVOIDING_OBSTACLE // Executing the timed detour
};

RobotState current_state = STATE_IDLE;


float last_error = 0;
bool has_cargo = false; // Tracks if robot is carrying a load
// NEW: Non-blocking timing variables
unsigned long detour_start_time = 0;
unsigned long lift_start_time = 0;
int detour_step = 0;
bool is_lifting = false;

// Sensor Calibration Arrays


int cal_min[NUM_SENSORS];
int cal_max[NUM_SENSORS];

// NEW: QR buffer to prevent data loss


String qr_buffer = "";

// --- 4. MOTOR CONTROL FUNCTIONS ---

void set_motor_speeds(int left_pwm, int right_pwm) {


// ADDED: Safety constraints
left_pwm = constrain(left_pwm, -MAX_SPEED, MAX_SPEED);
right_pwm = constrain(right_pwm, -MAX_SPEED,
MAX_SPEED);

// Left Motor Direction


digitalWrite(L_DIR, left_pwm >= 0 ? HIGH : LOW);
analogWrite(L_PWM, abs(left_pwm));

// Right Motor Direction


digitalWrite(R_DIR, right_pwm >= 0 ? HIGH : LOW);
analogWrite(R_PWM, abs(right_pwm));
}

void stop_motors() {
set_motor_speeds(0, 0);
}

// NEW: Non-blocking turn function for detour sequence


void start_detour_sequence() {
detour_start_time = millis();
detour_step = 1;
[Link]("Detour Step 1: Turning Left...");
set_motor_speeds(-DETOUR_SPEED, DETOUR_SPEED);
}

// MODIFIED: Non-blocking lift control


void start_lifting_mechanism(bool lift_up) {
[Link](lift_up ? "STARTING LIFT..." : "STARTING
DROP...");

// Set direction
if (lift_up) {
digitalWrite(LIFT_IN1, HIGH);
digitalWrite(LIFT_IN2, LOW);
} else {
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, HIGH);
}

// Start motor
analogWrite(LIFT_PWM, LIFT_SPEED);
lift_start_time = millis();
is_lifting = true;
}

void stop_lifting_mechanism() {
analogWrite(LIFT_PWM, 0);
digitalWrite(LIFT_IN1, LOW);
digitalWrite(LIFT_IN2, LOW);
is_lifting = false;
}

// --- 5. CALIBRATION AND SENSOR PROCESSING ---

void calibrate_sensors() {
stop_motors();
[Link]("--- CALIBRATION PHASE (10 seconds) ---");
[Link]("Move sensors over black line and white
surface.");

for (int i = 0; i < NUM_SENSORS; i++) {


cal_min[i] = 1023;
cal_max[i] = 0;
}

unsigned long startTime = millis();


while (millis() - startTime < 10000) {
for (int i = 0; i < NUM_SENSORS; i++) {
int reading = analogRead(QTR_PINS[i]);
if (reading < cal_min[i]) cal_min[i] = reading;
if (reading > cal_max[i]) cal_max[i] = reading;
}
delay(50);
}

[Link]("CALIBRATION COMPLETE. Starting run in 2


seconds.");
delay(2000);
}
// FIXED: Improved line sensor reading with better obstacle
detection
float read_line_sensors() {
long sum_weighted_values = 0;
long sum_normalized_values = 0;
bool line_detected = false;

for (int i = 0; i < NUM_SENSORS; i++) {


int raw_reading = analogRead(QTR_PINS[i]);

// Normalize reading (0.0 = White to 1.0 = Black)


float range = (float)(cal_max[i] - cal_min[i]);
if (range < 50) range = 50; // Safety against poor
calibration

float normalized_value = constrain((raw_reading -


cal_min[i]) / range, 0.0, 1.0);

// Apply weights: Sensor 0 = -7000, Sensor 7 = +7000


int position_weight = (i * 2000) - 7000;

sum_weighted_values += (long)(normalized_value *
position_weight);
sum_normalized_values += (long)(normalized_value *
1000);

// Check if any sensor sees the line strongly


if (normalized_value > 0.5) {
line_detected = true;
}
}

// FIXED: Better obstacle detection logic


if (!line_detected && sum_normalized_values <
LINE_LOST_THRESHOLD) {
// Line truly lost - obstacle detected
if (current_state == STATE_LINE_FOLLOWING) {
current_state = STATE_AVOIDING_OBSTACLE;
return 0;
}
}

// Calculate error only if we have sufficient sensor data


if (sum_normalized_values > 500) { // Increased minimum
threshold
return (float)sum_weighted_values /
sum_normalized_values;
} else {
// Return last error to maintain course briefly
return last_error * 0.7; // Dampened last error
}
}

// --- 6. OBSTACLE AVOIDANCE LOGIC ---

// NEW: Non-blocking detour execution


void update_detour_sequence() {
unsigned long current_time = millis();
unsigned long elapsed = current_time - detour_start_time;

switch (detour_step) {
case 1: // Turning left
if (elapsed >= DETOUR_TURN_TIME_MS) {
detour_step = 2;
detour_start_time = current_time;
[Link]("Detour Step 2: Moving Forward...");
set_motor_speeds(DETOUR_SPEED, DETOUR_SPEED);
}
break;

case 2: // Moving forward


if (elapsed >= DETOUR_FORWARD_TIME_MS) {
detour_step = 3;
detour_start_time = current_time;
[Link]("Detour Step 3: Turning Right to Re-
acquire Line...");
set_motor_speeds(DETOUR_SPEED, -DETOUR_SPEED);
}
break;

case 3: // Turning right to re-acquire


if (elapsed >= DETOUR_RE_ACQUIRE_TURN_MS) {
detour_step = 0;
current_state = STATE_LINE_FOLLOWING;
last_error = 0;
stop_motors();
[Link]("!!! DETOUR COMPLETE. RESUMING LINE
TRACKING. !!!");
}
break;
}
}

// --- 7. LOGISTICS TASK HANDLER (QR Code) ---

// MODIFIED: Improved QR handling with buffer


void handle_logistics_task(String qr_command) {
current_state = STATE_PERFORMING_TASK;
stop_motors();
[Link]("QR Code Scanned: ");
[Link](qr_command);

if (qr_command.startsWith("P")) {
// Pickup instruction
if (!has_cargo) {
start_lifting_mechanism(true);
} else {
[Link]("Already carrying cargo, skipping
pickup.");
current_state = STATE_LINE_FOLLOWING;
}
}
else if (qr_command.startsWith("D")) {
// Drop-off instruction
if (has_cargo) {
start_lifting_mechanism(false);
} else {
[Link]("No cargo to drop, skipping drop-off.");
current_state = STATE_LINE_FOLLOWING;
}
}
else {
[Link]("Unknown QR command. Task skipped.");
current_state = STATE_LINE_FOLLOWING;
}
}

// MODIFIED: Improved QR scanner with buffer


void check_qr_scanner() {
// Only process QR codes when not performing critical
maneuvers
if (current_state != STATE_AVOIDING_OBSTACLE &&
QR_SERIAL.available() > 0) {
while (QR_SERIAL.available() > 0) {
char c = QR_SERIAL.read();
if (c == '\n' || c == '\r') {
if (qr_buffer.length() > 0) {
// Process complete command
if (qr_buffer.startsWith("P") ||
qr_buffer.startsWith("D")) {
handle_logistics_task(qr_buffer);
}
qr_buffer = "";
}
} else {
qr_buffer += c;
}
}
}
}

// --- 8. ARDUINO SETUP ---

void setup() {
// Initialize Communication
[Link](9600);
QR_SERIAL.begin(9600);
[Link]("ALR Master Program Initialized.");

// Configure Drive Motor Pins


pinMode(L_PWM, OUTPUT); pinMode(L_DIR, OUTPUT);
pinMode(R_PWM, OUTPUT); pinMode(R_DIR, OUTPUT);

// Configure Lifting Mechanism Pins


pinMode(LIFT_PWM, OUTPUT);
pinMode(LIFT_IN1, OUTPUT);
pinMode(LIFT_IN2, OUTPUT);

// Configure Start Switch Pin


pinMode(START_SWITCH_PIN, INPUT_PULLUP);

// Initialize motor states


stop_motors();
stop_lifting_mechanism();

// Perform sensor calibration


calibrate_sensors();

// Wait for start switch


[Link]("WAITING FOR START SWITCH...");
while (digitalRead(START_SWITCH_PIN) == HIGH) {
delay(10);
}

current_state = STATE_LINE_FOLLOWING;
[Link]("START SWITCH ACTIVATED. Entering Line
Following State.");
}

// --- 9. ARDUINO MAIN LOOP ---

void loop() {
// Always check for QR codes
check_qr_scanner();

// Handle lifting mechanism completion


if (is_lifting && (millis() - lift_start_time >=
LIFT_DURATION_MS)) {
stop_lifting_mechanism();
if (has_cargo) {
has_cargo = false;
[Link]("CARGO DROPPED. STATUS: Empty.");
} else {
has_cargo = true;
[Link]("CARGO LIFTED. STATUS: Loaded.");
}
current_state = STATE_LINE_FOLLOWING;
}

switch (current_state) {
case STATE_LINE_FOLLOWING: {
float error = read_line_sensors();

// If state changed to AVOIDING, break and let next case


handle it
if (current_state == STATE_AVOIDING_OBSTACLE) {
start_detour_sequence();
break;
}

// Calculate PD Correction
float P_term = Kp * error;
float derivative = error - last_error;
float D_term = Kd * derivative;
float motor_correction = P_term + D_term;

// Apply Correction to Motors


int left_speed = BASE_SPEED - (int)motor_correction;
int right_speed = BASE_SPEED + (int)motor_correction;

// Constrain Speeds
left_speed = constrain(left_speed, MIN_SPEED,
MAX_SPEED);
right_speed = constrain(right_speed, MIN_SPEED,
MAX_SPEED);

// Execute Movement
set_motor_speeds(left_speed, right_speed);

// Store Current Error


last_error = error;
break;
}

case STATE_AVOIDING_OBSTACLE: {
update_detour_sequence();
break;
}
case STATE_PERFORMING_TASK:
// Motors already stopped, just wait for task completion
stop_motors();
break;

case STATE_IDLE:
stop_motors();
break;
}

// Small delay to prevent overwhelming the processor


delay(10);
}

You might also like