Created
February 9, 2026 08:04
-
-
Save ubdussamad/2ab5a127e43ad72f8dd1cea329dcf614 to your computer and use it in GitHub Desktop.
DAS-Lab-3-2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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