Skip to content

Instantly share code, notes, and snippets.

@ubdussamad
Created February 9, 2026 08:04
Show Gist options
  • Select an option

  • Save ubdussamad/2ab5a127e43ad72f8dd1cea329dcf614 to your computer and use it in GitHub Desktop.

Select an option

Save ubdussamad/2ab5a127e43ad72f8dd1cea329dcf614 to your computer and use it in GitHub Desktop.
DAS-Lab-3-2026
/*
* Design of Autonomous Systems Lab 3 Code (Spr'26)
* Sam Ul Haque
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <array>
#include <chrono>
#include <thread>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/gpio.h>
#include <csignal>
#include <atomic>
std::atomic<bool> running(true);
// GPIO pin definitions for the RGB LED
#define GPIO_RED 16
#define GPIO_GREEN 19
#define GPIO_BLUE 20
// Ultrasonic pins
#define ULTRASONIC_TRIG 23
#define ULTRASONIC_ECHO 24
static int out_fd = -1, in_fd = -1;
static gpiohandle_data out_state{}; // persistent output state
static std::array<int, 64> out_idx, in_idx; // pin -> index (or -1)
std::atomic<float> distance(0.0); // Shared variable for distance measurement
static bool init() {
if (out_fd >= 0 && in_fd >= 0) return true;
out_idx.fill(-1);
in_idx.fill(-1);
memset(&out_state, 0, sizeof(out_state));
int OUT_PINS[] = {GPIO_RED, GPIO_GREEN, GPIO_BLUE, ULTRASONIC_TRIG};
int IN_PINS[] = {ULTRASONIC_ECHO};
int chip_fd = open("/dev/gpiochip0", O_RDONLY);
if (chip_fd < 0) { perror("open gpiochip0"); return false; }
int tmp_out_fd = -1, tmp_in_fd = -1;
gpiohandle_data tmp_out_state{};
// outputs
{
gpiohandle_request req{};
req.lines = (int)(sizeof(OUT_PINS)/sizeof(OUT_PINS[0]));
req.flags = GPIOHANDLE_REQUEST_OUTPUT;
strcpy(req.consumer_label, "outs");
for (int i = 0; i < req.lines; i++) {
int pin = OUT_PINS[i];
req.lineoffsets[i] = pin;
req.default_values[i] = 0;
if (pin >= 0 && pin < (int)out_idx.size()) out_idx[pin] = i;
}
if (ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
perror("GET_LINEHANDLE outs (This can be ignored!)");
close(chip_fd);
return false;
}
tmp_out_fd = req.fd;
tmp_out_state = gpiohandle_data{}; // start all low
}
// inputs
{
gpiohandle_request req{};
req.lines = (int)(sizeof(IN_PINS)/sizeof(IN_PINS[0]));
req.flags = GPIOHANDLE_REQUEST_INPUT;
strcpy(req.consumer_label, "ins");
for (int i = 0; i < req.lines; i++) {
int pin = IN_PINS[i];
req.lineoffsets[i] = pin;
if (pin >= 0 && pin < (int)in_idx.size()) in_idx[pin] = i;
}
if (ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0) {
perror("GET_LINEHANDLE ins");
// important: release outputs if inputs fail
if (tmp_out_fd >= 0) close(tmp_out_fd);
close(chip_fd);
return false;
}
tmp_in_fd = req.fd;
}
close(chip_fd);
// commit only when both succeeded
out_fd = tmp_out_fd;
in_fd = tmp_in_fd;
out_state = tmp_out_state;
return true;
}
static void write_pin(int pin, int v) {
init();
int idx = (pin >= 0 && pin < (int)out_idx.size()) ? out_idx[pin] : -1;
if (idx < 0) { fprintf(stderr, "pin %d not in OUT_PINS\n", pin); return; }
out_state.values[idx] = v ? 1 : 0;
if (ioctl(out_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &out_state) < 0)
perror("SET_LINE_VALUES");
}
static int read_pin(int pin) {
init();
int idx = (pin >= 0 && pin < (int)in_idx.size()) ? in_idx[pin] : -1;
if (idx < 0) { fprintf(stderr, "pin %d not in IN_PINS\n", pin); return -1; }
gpiohandle_data in_data{};
if (ioctl(in_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &in_data) < 0) {
perror("GET_LINE_VALUES"); return -1;
}
return in_data.values[idx];
}
void readSensor() {
while (running.load()) {
// Trigger the ultrasonic sensor and read the distance
// Update the shared atomic variable 'distance' with the new measurement
write_pin(ULTRASONIC_TRIG, 1);
usleep(10); // Trigger pulse
write_pin(ULTRASONIC_TRIG, 0);
// std::cout << "Ultrasonic sensor triggered, waiting for echo...\n";
// Wait for echo and calculate distance
auto startTime = std::chrono::high_resolution_clock::now();
auto endTime = startTime;
while (!read_pin(ULTRASONIC_ECHO) && running.load()) { // Wait for echo to go high
auto startTime = std::chrono::high_resolution_clock::now();
}
// std::cout << "Echo received, measuring distance...\n";
while (read_pin(ULTRASONIC_ECHO) && running.load()) { // Wait for echo to go low
auto endTime = std::chrono::high_resolution_clock::now();
}
// std::cout << "Echo ended, calculating distance...\n";
// Calculate distance based on time difference and update the atomic variable
auto delta = endTime - startTime; // Convert to distance
float distanceValue = std::chrono::duration_cast<std::chrono::microseconds>(delta).count() * 0.034 / 2; // Speed of sound calculation
distance.store(distanceValue); // Update the shared atomic variable
// Print distance with specific number of digits
std::cout << "Distance measured: " << std::fixed << std::setprecision(2) << distanceValue << " cm\r";
std::cout.flush();
}
std::cout << "Sensor reading thread exiting...\n";
}
void flashLED() {
const float threshold = 20.0; // Distance threshold in cm
while (running.load()) {
float currentDistance = distance.load(); // Read the shared atomic variable
if (currentDistance < threshold) {
// Flash the LED
write_pin(GPIO_RED, 1); // Turn on red LED
usleep(50000); // Wait for 500ms
write_pin(GPIO_RED, 0); // Turn off red LED
usleep(50000); // Wait for 500ms
write_pin(GPIO_RED, 1); // Turn on red LED
usleep(50000); // Wait for 500ms
write_pin(GPIO_RED, 0); // Turn off red LED
usleep(500000); // Wait for 500ms
}
}
std::cout << "LED flashing thread exiting...\n";
}
void cleanup() {
std::cout << "\nCleaning up GPIO...\n";
// Turn everything OFF
if (out_fd >= 0) {
for (int i = 0; i < 64; i++) {
if (out_idx[i] >= 0)
out_state.values[out_idx[i]] = 0;
}
ioctl(out_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &out_state);
close(out_fd);
out_fd = -1;
}
if (in_fd >= 0) {
close(in_fd);
in_fd = -1;
}
std::cout << "GPIO released. Bye!\n";
}
void signal_handler(int sig) {
if (sig == SIGINT) {
running.store(false);
}
}
int main() {
signal(SIGINT, signal_handler);
// Start the sensor reading thread
std::thread sensorThread(readSensor);
// Start the LED flashing thread
std::thread ledThread(flashLED);
// Join threads (optional, as they run indefinitely)
sensorThread.join();
ledThread.join();
cleanup();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment