# ==============================================================================

# CATEGORY: RASPBERRY PI CODES

# ==============================================================================



# ------------------------------------------------------------------------------

# LAB-1 Ultra Sonic Sensor

# Distance Measurement Between Object and Sensor Using Raspberry Pi and Buzzer

#

# HOW TO RUN:

# 1. Connect HC-SR04 Trigger to GPIO 23, Echo to GPIO 24 (via voltage divider),

#    and Buzzer to GPIO 18 on the Raspberry Pi.

# 2. Open terminal and run: python3 lab1_ultrasonic.py

# 3. Press Ctrl+C to stop the program.

# ------------------------------------------------------------------------------



import RPi.GPIO as GPIO

import time



TRIG = 23

ECHO = 24

BUZZER = 18

THRESHOLD = 10



GPIO.setmode(GPIO.BCM)

GPIO.setup(TRIG, GPIO.OUT)

GPIO.setup(ECHO, GPIO.IN)

GPIO.setup(BUZZER, GPIO.OUT)



GPIO.output(TRIG, False)

GPIO.output(BUZZER, False)

time.sleep(2)



try:

    while True:

        GPIO.output(TRIG, True)

        time.sleep(0.00001)

        GPIO.output(TRIG, False)



        while GPIO.input(ECHO) == 0:

            pulse_start = time.time()



        while GPIO.input(ECHO) == 1:

            pulse_end = time.time()



        pulse_duration = pulse_end - pulse_start

        distance_cm = round(pulse_duration * 17150, 2)

        distance_in = round(distance_cm / 2.54, 2)



        print(f"Distance: {distance_cm} cm | {distance_in} in")



        if distance_cm <= THRESHOLD:

            GPIO.output(BUZZER, True)

        else:

            GPIO.output(BUZZER, False)



        time.sleep(0.5)



except KeyboardInterrupt:

    print("Measurement stopped.")

    GPIO.cleanup()





# ------------------------------------------------------------------------------

# LAB-3 Intelligent 4-Road (4-Way) Traffic Light Controller

#

# HOW TO RUN:

# 1. Wire 12 LEDs (R, Y, G for 4 roads) to the corresponding Raspberry Pi GPIO pins:

#    - Road 1: R=17, Y=27, G=22

#    - Road 2: R=10, Y=9, G=11

#    - Road 3: R=5, Y=6, G=13

#    - Road 4: R=19, Y=26, G=21

# 2. Open terminal and execute: python3 fourway.py

# 3. Enter vehicle counts per road when prompted in the terminal.

# 4. Press Ctrl+C to terminate safely.

# ------------------------------------------------------------------------------



import time

from gpiozero import LED



# Hardware mapping grouped by road

roads = {

    1: {'R': LED(17), 'Y': LED(27), 'G': LED(22)},

    2: {'R': LED(10), 'Y': LED(9), 'G': LED(11)},

    3: {'R': LED(5), 'Y': LED(6), 'G': LED(13)},

    4: {'R': LED(19), 'Y': LED(26), 'G': LED(21)}

}



# Configuration Constants

MIN_GREEN = 3.0

TIME_PER_CAR = 0.5

MAX_GREEN = 45.0

YELLOW_TIME = 2.0

BUFFER_TIME = 1.0



def get_green_duration(cars):

    return min(MIN_GREEN + (cars * TIME_PER_CAR), MAX_GREEN)



def set_all_red():

    for r in roads.values():

        r['G'].off()

        r['Y'].off()

        r['R'].on()



try:

    while True:

        print("\n--- Update 4-Road Intersection Traffic Matrix ---")

        car_counts = {}

        for i in range(1, 5):

            try:

                count = int(input(f"Enter vehicle density for Road {i}: "))

                car_counts[i] = max(0, count)

            except ValueError:

                print("Invalid input. Defaulting to 0.")

                car_counts[i] = 0



        # Run sequential green intervals for each road

        for active_id in range(1, 5):

            green_len = get_green_duration(car_counts[active_id])



            # Step A: Enforce global safe baseline

            set_all_red()

            time.sleep(BUFFER_TIME)



            # Step B: Trigger Green phase for targeted road

            print(f"[Road {active_id}] STATUS: GREEN for {green_len}s")

            roads[active_id]['R'].off()

            roads[active_id]['G'].on()

            time.sleep(green_len)



            # Step C: Trigger Yellow caution phase

            print(f"[Road {active_id}] STATUS: YELLOW for {YELLOW_TIME}s")

            roads[active_id]['G'].off()

            roads[active_id]['Y'].on()

            time.sleep(YELLOW_TIME)



except KeyboardInterrupt:

    print("\nShutting down controller safely...")

    for r in roads.values():

        r['R'].off()

        r['Y'].off()

        r['G'].off()





# ------------------------------------------------------------------------------

# LAB-4 Binary Classification

# Part 1: Dataset Creation (Image Capture)

#

# HOW TO RUN:

# 1. Connect Raspberry Pi Camera Module.

# 2. Run: python3 capture_dataset.py

# 3. Change `category` variable to "Pen" or "Other" depending on desired target.

# 4. Press ENTER to take photos, or 'q' + ENTER to exit.

# ------------------------------------------------------------------------------



import os

import subprocess



category = "Other"  # Change to "Pen" while collecting pen images

save_dir = os.path.join("dataset", category)

os.makedirs(save_dir, exist_ok=True)



img_count = len(os.listdir(save_dir))

print("=" * 50)

print(f"Saving photos to: {save_dir}")

print("Press ENTER to capture image")

print("Press q + ENTER to quit")

print("=" * 50)



while True:

    user_input = input(f"[Captured: {img_count}] Press ENTER to capture (or q): ")

    if user_input.strip().lower() == "q":

        break

    img_name = os.path.join(save_dir, f"img_{img_count:03d}.jpg")

    cmd = ["rpicam-still", "-t", "1", "-o", img_name, "--nopreview"]

    try:

        subprocess.run(cmd, check=True)

        print(f"Saved -> {img_name}")

        img_count += 1

    except Exception as e:

        print(e)

        break



print("Dataset Collection Finished")





# ------------------------------------------------------------------------------

# LAB-4 Binary Classification

# Part 2: Training and Live Classification

#

# HOW TO RUN:

# 1. Ensure `dataset/Pen` and `dataset/Other` directories are populated with images.

# 2. Run: python3 train_and_classify.py

# 3. Press ENTER in the OpenCV window to classify current live frame; press 'q' to exit.

# ------------------------------------------------------------------------------



import os

import cv2

import numpy as np

from sklearn.neural_network import MLPClassifier



data_dir = "dataset"

categories = ["Other", "Pen"]

img_size = 64

features = []

labels = []



# Load Dataset

for category in categories:

    path = os.path.join(data_dir, category)

    class_num = categories.index(category)

    for img_name in os.listdir(path):

        img_path = os.path.join(path, img_name)

        img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)

        if img is None:

            continue

        resized = cv2.resize(img, (img_size, img_size))

        flattened = resized.flatten().astype(np.float32) / 255.0

        features.append(flattened)

        labels.append(class_num)



X = np.array(features)

y = np.array(labels)



# Train Model

model = MLPClassifier(hidden_layer_sizes=(32,), max_iter=500, random_state=42)

model.fit(X, y)

print("Model Trained Successfully")



temp_img = "current_view.jpg"



# Live Prediction

while True:

    os.system(f"rpicam-still -t 10 -o {temp_img} --nopreview --width 640 --height 480")

    frame = cv2.imread(temp_img)

    if frame is None:

        break



    cv2.putText(

        frame,

        "Press ENTER to Classify | Q to Quit",

        (20, 30),

        cv2.FONT_HERSHEY_SIMPLEX,

        0.6,

        (0, 255, 255),

        2

    )

    cv2.imshow("Pen Classifier", frame)

    key = cv2.waitKey(100)



    if key == ord('q'):

        break

    elif key == 13:  # ENTER key

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        resized = cv2.resize(gray, (img_size, img_size))

        flattened = resized.flatten().astype(np.float32) / 255.0

        prediction = model.predict([flattened])[0]

        label = "PEN" if prediction == 1 else "NOT PEN"

        print("Prediction:", label)



cv2.destroyAllWindows()





# ------------------------------------------------------------------------------

# LAB-5 Multiclass classification with camera module

#

# HOW TO RUN:

# 1. Install prerequisites: `pip install ultralytics opencv-python`

# 2. Attach Pi Camera / USB Webcam.

# 3. Run: python3 yolo_detection.py

# 4. Press 'q' to quit the live feed.

# ------------------------------------------------------------------------------



from ultralytics import YOLO

import cv2



# Load pre-trained YOLO model

model = YOLO("yolov8n.pt")



# Open Raspberry Pi camera

cap = cv2.VideoCapture(0)



if not cap.isOpened():

    print("Camera not found")

    exit()



print("Real-Time YOLO Object Detection")

print("Press Q to quit")



while True:

    ret, frame = cap.read()

    if not ret:

        print("Failed to capture frame")

        break



    # Run YOLO detection

    results = model(frame, conf=0.5)



    # Draw detections

    annotated_frame = results[0].plot()



    # Display result

    cv2.imshow("YOLO COCO - Raspberry Pi Camera", annotated_frame)



    if cv2.waitKey(1) & 0xFF == ord('q'):

        break



cap.release()

cv2.destroyAllWindows()

print("Program terminated")





# ==============================================================================

# CATEGORY: Arduino Smart Car Parking System (Lab Assignment - 2)

# ==============================================================================

#

# HOW TO RUN:

# 1. Connect Entry IR Sensor to Pin 2, Exit IR Sensor to Pin 3, Buzzer to Pin 4 on Arduino.

# 2. Open Arduino IDE, compile and upload the code to Arduino Uno.

# 3. Open Serial Monitor at 9600 baud rate to view live status.

# ------------------------------------------------------------------------------



/*

// Arduino Code C++

const int entrySensor = 2; // IR Sensor at the entrance

const int exitSensor = 3;  // IR Sensor at the exit

const int buzzer = 4;      // Alarm Buzzer



int freeSpace = 10;

bool carEntering = false;

bool carExiting = false;



void setup() {

  Serial.begin(9600);

  pinMode(entrySensor, INPUT);

  pinMode(exitSensor, INPUT);

  pinMode(buzzer, OUTPUT);



  Serial.println("--- Smart Parking System Initialized ---");

  printStatus();

}



void loop() {

  int entryState = digitalRead(entrySensor);

  int exitState = digitalRead(exitSensor);



  // ENTRY LOGIC

  if (entryState == LOW && !carEntering) {

    carEntering = true;

    if (freeSpace > 0) {

      freeSpace--;

      Serial.println("Car Entered.");

      printStatus();

    } else {

      Serial.println("Access Denied: Parking Full!");

      digitalWrite(buzzer, HIGH);

      delay(1000);

      digitalWrite(buzzer, LOW);

    }

  }



  if (entryState == HIGH) {

    carEntering = false;

  }



  // EXIT LOGIC

  if (exitState == LOW && !carExiting) {

    carExiting = true;

    if (freeSpace < 10) {

      freeSpace++;

      Serial.println("Car Exited.");

      printStatus();

    } else {

      Serial.println("Error: System already at max capacity!");

    }

  }



  if (exitState == HIGH) {

    carExiting = false;

  }



  delay(50);

}



void printStatus() {

  Serial.print("Free Spaces Available: ");

  Serial.println(freeSpace);

  if (freeSpace == 0) {

    Serial.println("STATUS: [PARKING FULL]");

  }

  Serial.println("---");

}

*/





# ==============================================================================

# CATEGORY: Robo Car (Lab Assignment - 6)

# ==============================================================================



# ------------------------------------------------------------------------------

# 1. Square Motion

#

# HOW TO RUN:

# 1. Wire L298N Motor Driver pins ENA=6, IN1=7, IN2=8, IN3=9, IN4=11, ENB=5 to Arduino.

# 2. Upload code via Arduino IDE. Place robot on flat surface and power on.

# ------------------------------------------------------------------------------



/*

#define ENB 5

#define IN1 7

#define IN2 8

#define IN3 9

#define IN4 11

#define ENA 6



int speedL = 150;

int speedR = 150;

int forwardTime = 2000;

int turnTime = 650;



void setup() {

  pinMode(ENB, OUTPUT);

  pinMode(IN1, OUTPUT);

  pinMode(IN2, OUTPUT);

  pinMode(IN3, OUTPUT);

  pinMode(IN4, OUTPUT);

  pinMode(ENA, OUTPUT);



  stopBot();

  delay(2000);

}



void loop() {

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

    forward();

    delay(forwardTime);

    stopBot();

    delay(300);

    turnRight();

    delay(turnTime);

    stopBot();

    delay(300);

  }



  while (true) {

    stopBot();

  }

}



void forward() {

  analogWrite(ENA, speedL);

  analogWrite(ENB, speedR);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, HIGH);

}



void turnRight() {

  analogWrite(ENA, speedL);

  analogWrite(ENB, speedR);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, HIGH);

  digitalWrite(IN4, LOW);

}



void stopBot() {

  analogWrite(ENA, 0);

  analogWrite(ENB, 0);

  digitalWrite(IN1, LOW);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, LOW);

}

*/





# ------------------------------------------------------------------------------

# 2. Circle Motion

#

# HOW TO RUN:

# 1. Connect motor driver pins to Arduino as defined.

# 2. Upload code via Arduino IDE.

# ------------------------------------------------------------------------------



/*

#define ENB 5

#define IN1 7

#define IN2 8

#define IN3 9

#define IN4 11

#define ENA 6



int leftSpeed = 170;

int rightSpeed = 80;

int circleTime = 4500;



void setup() {

  pinMode(ENB, OUTPUT);

  pinMode(IN1, OUTPUT);

  pinMode(IN2, OUTPUT);

  pinMode(IN3, OUTPUT);

  pinMode(IN4, OUTPUT);

  pinMode(ENA, OUTPUT);



  stopBot();

  delay(2000);

}



void loop() {

  circle();

  stopBot();

  while (true) {

    stopBot();

  }

}



void circle() {

  analogWrite(ENA, leftSpeed);

  analogWrite(ENB, rightSpeed);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, HIGH);

  delay(circleTime);

}



void stopBot() {

  analogWrite(ENA, 0);

  analogWrite(ENB, 0);

  digitalWrite(IN1, LOW);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, LOW);

}

*/





# ------------------------------------------------------------------------------

# 3. Line Following

#

# HOW TO RUN:

# 1. Connect 3 IR sensors: LT_L = Pin 2, LT_M = Pin 4, LT_R = Pin 10.

# 2. Connect motor driver to pins 5, 6, 7, 8, 9, 11.

# 3. Upload code to Arduino and place robot on black line track.

# ------------------------------------------------------------------------------



/*

#define LT_L 2

#define LT_M 4

#define LT_R 10

#define ENB 5

#define IN1 7

#define IN2 8

#define IN3 9

#define IN4 11

#define ENA 6



const int BASE_SPEED = 100;

const int SLOW_SPEED = 20;

const int FAST_SPEED = 140;

const int SEARCH_SPEED = 120;



void setup() {

  pinMode(LT_L, INPUT);

  pinMode(LT_M, INPUT);

  pinMode(LT_R, INPUT);

  pinMode(ENB, OUTPUT);

  pinMode(IN1, OUTPUT);

  pinMode(IN2, OUTPUT);

  pinMode(IN3, OUTPUT);

  pinMode(IN4, OUTPUT);

  pinMode(ENA, OUTPUT);



  stopBot();

  delay(2000);

}



void loop() {

  int leftState = digitalRead(LT_L);

  int middleState = digitalRead(LT_M);

  int rightState = digitalRead(LT_R);



  if (leftState == LOW && middleState == HIGH && rightState == LOW) {

    forward(BASE_SPEED, BASE_SPEED);

  }

  else if (leftState == HIGH && rightState == LOW) {

    forward(SLOW_SPEED, FAST_SPEED);

  }

  else if (leftState == LOW && rightState == HIGH) {

    forward(FAST_SPEED, SLOW_SPEED);

  }

  else if (leftState == LOW && middleState == LOW && rightState == LOW) {

    spinSearchRight();

  }

  else if (leftState == HIGH && middleState == HIGH && rightState == HIGH) {

    forward(BASE_SPEED, BASE_SPEED);

  }

}



void forward(int speedLeft, int speedRight) {

  analogWrite(ENA, speedLeft);

  analogWrite(ENB, speedRight);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, HIGH);

}



void spinSearchRight() {

  analogWrite(ENA, SEARCH_SPEED);

  analogWrite(ENB, SEARCH_SPEED);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, HIGH);

  digitalWrite(IN4, LOW);

}



void stopBot() {

  analogWrite(ENA, 0);

  analogWrite(ENB, 0);

  digitalWrite(IN1, LOW);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, LOW);

}

*/





# ------------------------------------------------------------------------------

# 4. Maze Solving Using Ultrasonic Sensor

#

# HOW TO RUN:

# 1. Connect Ultrasonic Sensor: TRIG_PIN = A0, ECHO_PIN = A1.

# 2. Upload code to Arduino and place robot inside the maze.

# ------------------------------------------------------------------------------



/*

#define ENB 5

#define IN1 7

#define IN2 8

#define IN3 9

#define IN4 11

#define ENA 6

#define TRIG_PIN A0

#define ECHO_PIN A1



const int SPEED = 120;

const int TURN_SPEED = 140;

const int SAFE_DISTANCE = 25;

const int TURN_TIME = 500;

const int UTURN_TIME = 1000;



void setup() {

  pinMode(ENB, OUTPUT);

  pinMode(IN1, OUTPUT);

  pinMode(IN2, OUTPUT);

  pinMode(IN3, OUTPUT);

  pinMode(IN4, OUTPUT);

  pinMode(ENA, OUTPUT);

  pinMode(TRIG_PIN, OUTPUT);

  pinMode(ECHO_PIN, INPUT);



  stopBot();

  delay(2000);

}



void loop() {

  int front = getDistance();

  if (front > SAFE_DISTANCE) {

    forward();

  } else {

    stopBot();

    delay(200);



    turnLeft();

    delay(TURN_TIME);

    stopBot();

    delay(100);

    int left = getDistance();



    turnRight();

    delay(TURN_TIME);

    stopBot();

    delay(100);



    turnRight();

    delay(TURN_TIME);

    stopBot();

    delay(100);

    int right = getDistance();



    turnLeft();

    delay(TURN_TIME);

    stopBot();

    delay(100);



    if (left > SAFE_DISTANCE && left >= right) {

      turnLeft();

      delay(TURN_TIME);

    } else if (right > SAFE_DISTANCE) {

      turnRight();

      delay(TURN_TIME);

    } else {

      turnRight();

      delay(UTURN_TIME);

    }

    stopBot();

    delay(100);

  }

}



int getDistance() {

  digitalWrite(TRIG_PIN, LOW);

  delayMicroseconds(2);

  digitalWrite(TRIG_PIN, HIGH);

  delayMicroseconds(10);

  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000);

  if (duration == 0) {

    return 400;

  }

  int distance = duration * 0.034 / 2;

  return distance;

}



void forward() {

  analogWrite(ENA, SPEED);

  analogWrite(ENB, SPEED);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, HIGH);

}



void turnRight() {

  analogWrite(ENA, TURN_SPEED);

  analogWrite(ENB, TURN_SPEED);

  digitalWrite(IN1, HIGH);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, HIGH);

  digitalWrite(IN4, LOW);

}



void turnLeft() {

  analogWrite(ENA, TURN_SPEED);

  analogWrite(ENB, TURN_SPEED);

  digitalWrite(IN1, LOW);

  digitalWrite(IN2, HIGH);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, HIGH);

}



void stopBot() {

  analogWrite(ENA, 0);

  analogWrite(ENB, 0);

  digitalWrite(IN1, LOW);

  digitalWrite(IN2, LOW);

  digitalWrite(IN3, LOW);

  digitalWrite(IN4, LOW);

}

*/





# ==============================================================================

# CATEGORY: TurtleBot Simulation Assignment (Lab Assignment - 7)

# ==============================================================================

#

# HOW TO RUN ROS 2 COMMANDS:

# 1. Make sure ROS 2 (Humble/Iron/Jazzy) is sourced in your Linux terminal.

# 2. Run commands in separate terminal windows as outlined below.

# ------------------------------------------------------------------------------



# --- 1. Turtle Sim Teleoperation ---

# Terminal 1: Launch Turtlesim Simulator

# ros2 run turtlesim turtlesim_node



# Terminal 2: Run Teleop Key Node

# ros2 run turtlesim turtle_teleop_key



# --- 1.1 Topic Data View ---

# List active nodes and topics:

# ros2 node list

# ros2 topic list



# Echo pose and command velocity data:

# ros2 topic echo /turtle1/pose

# ros2 topic echo /turtle1/cmd_vel



# Check topic information:

# ros2 topic info /turtle1/cmd_vel



# --- 1.2 Record Topic Data ---

# Record specific topics into ROS bag files:

# ros2 bag record /turtle1/cmd_vel

# ros2 bag record -o my_cmd_vel_bag /turtle1/cmd_vel

# ros2 bag record /scan

# ros2 bag record -o scan_data_bag /scan

# ros2 bag record -a



# Pipe topic stream into a text file:

# ros2 topic echo /scan > scan_output.txt



# Inspect bag file info:

# ros2 bag info <bag_file_folder_name>



# --- 2. Three Turtle Simultaneous Movement ---

# Run velocity publish commands simultaneously across three turtle namespaces:

# ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"

# ros2 topic pub /turtle2/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"

# ros2 topic pub /turtle3/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"



# --- 3. Three Turtle One-by-One Movement ---

# Run commands sequentially (one after another):

# ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"

# ros2 topic pub --once /turtle2/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"

# ros2 topic pub --once /turtle3/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0}, angular: {z: 1.0}}"