diff --git a/ESP/mqtt_test/mqtt_test.ino b/ESP/mqtt_test/mqtt_test.ino index 81157d1..007da7e 100644 --- a/ESP/mqtt_test/mqtt_test.ino +++ b/ESP/mqtt_test/mqtt_test.ino @@ -8,7 +8,8 @@ const char* mqttServer = "10.1.13.173"; const int mqttPort = 1883; const char* mqttTopic = "test"; -const int gpioPin = 25; // GPIO pin to check for shorting +const int gpioPins[] = {25, 26, 27, 14}; // GPIO pins to check for shorting +const unsigned int numPins = sizeof(gpioPins) / sizeof(gpioPins[0]); const unsigned long debounceDelay = 50; // Debounce delay in milliseconds WiFiClient wifiClient; @@ -16,9 +17,7 @@ PubSubClient mqttClient(wifiClient); TaskHandle_t mqttTaskHandle = NULL; -Bounce debouncer = Bounce(); - -volatile int pressCounter = 0; +Bounce debouncers[numPins]; void setupWiFi() { WiFi.begin(ssid, password); @@ -54,25 +53,30 @@ void mqttTask(void* parameter) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // Wait for notification if (mqttClient.connected()) { - String message = "GPIO pin shorted! Count: " + String(pressCounter); - mqttClient.publish(mqttTopic, message.c_str()); - Serial.println("Message sent to MQTT server"); - pressCounter++; + for (unsigned int i = 0; i < numPins; i++) { + if (debouncers[i].fell()) { + String message = "Pin shorted: " + String(gpioPins[i]); + mqttClient.publish(mqttTopic, message.c_str()); + Serial.println("Message sent to MQTT server"); + } + } } } } void setup() { Serial.begin(115200); - pinMode(gpioPin, INPUT_PULLUP); - - debouncer.attach(gpioPin); - debouncer.interval(debounceDelay); setupWiFi(); mqttClient.setServer(mqttServer, mqttPort); mqttClient.setCallback(callback); + for (unsigned int i = 0; i < numPins; i++) { + pinMode(gpioPins[i], INPUT_PULLUP); + debouncers[i].attach(gpioPins[i]); + debouncers[i].interval(debounceDelay); + } + xTaskCreatePinnedToCore( mqttTask, // Task function "mqttTask", // Task name @@ -90,8 +94,19 @@ void loop() { } mqttClient.loop(); - debouncer.update(); - if (debouncer.fell()) { + for (unsigned int i = 0; i < numPins; i++) { + debouncers[i].update(); + } + + bool anyPinShorted = false; + for (unsigned int i = 0; i < numPins; i++) { + if (debouncers[i].fell()) { + anyPinShorted = true; + break; + } + } + + if (anyPinShorted) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(mqttTaskHandle, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken == pdTRUE) { diff --git a/faces/prootface3.png b/faces/prootface3.png new file mode 100644 index 0000000..69b53fd Binary files /dev/null and b/faces/prootface3.png differ diff --git a/faces/prootface4.png b/faces/prootface4.png new file mode 100644 index 0000000..a765db5 Binary files /dev/null and b/faces/prootface4.png differ diff --git a/minDistance.py b/minDistance.py new file mode 100644 index 0000000..0bee9b6 --- /dev/null +++ b/minDistance.py @@ -0,0 +1,132 @@ +import math +from PIL import Image +import numpy as np +from scipy.optimize import linear_sum_assignment + + +class Point2D: + x = 0 + y = 0 + + def __init__(self, x, y): + self.x = x + self.y = y + + def round(self): + self.x = round(self.x) + self.y = round(self.y) + return self + + def distance(self, other): + dx = self.x - other.x + dy = self.y - other.y + return math.sqrt(dx**2 + dy**2) + + def interpolate(self, other, percentage): + new_x = self.x + (other.x - self.x) * percentage + new_y = self.y + (other.y - self.y) * percentage + return Point2D(new_x, new_y) + + def __eq__(self, other): + return (self.x, self.y) == (other.x, other.y) + + +def generate_point_array_from_image(image): + image = image.convert("RGB") # Convert image to RGB color mode + + width, height = image.size + point_array = [] + + # Iterate over the pixels and generate Point2D instances + for y in range(height): + for x in range(width): + pixel = image.getpixel((x, y)) + if pixel != (0, 0, 0): # Assuming white pixels + point = Point2D(x, y) + point_array.append(point) + + return point_array + + +def generate_image_from_point_array(points, width, height): + # Create a new blank image + image = Image.new("RGB", (width, height), "black") + + # Set the pixels corresponding to the points as white + pixels = image.load() + for point in points: + point = point.round() + x = point.x + y = point.y + pixels[x, y] = (255, 255, 255) + + return image + + +def pair_points(points1, points2): + # Determine the size of the point arrays + size1 = len(points1) + size2 = len(points2) + + # Create a cost matrix based on the distances between points + cost_matrix = np.zeros((size1, size2)) + for i in range(size1): + for j in range(size2): + cost_matrix[i, j] = points1[i].distance(points2[j]) + + # Duplicate points in the smaller array to match the size of the larger array + if size1 > size2: + num_duplicates = size1 - size2 + duplicated_points = np.random.choice(points2, size=num_duplicates).tolist() + points2 += duplicated_points + elif size2 > size1: + num_duplicates = size2 - size1 + duplicated_points = np.random.choice(points1, size=num_duplicates).tolist() + points1 += duplicated_points + + # Update the size of the point arrays + size1 = len(points1) + size2 = len(points2) + + # Create a new cost matrix with the updated sizes + cost_matrix = np.zeros((size1, size2)) + for i in range(size1): + for j in range(size2): + cost_matrix[i, j] = points1[i].distance(points2[j]) + + # Solve the assignment problem using the Hungarian algorithm + row_ind, col_ind = linear_sum_assignment(cost_matrix) + + # Create pairs of points based on the optimal assignment + pairs = [] + for i, j in zip(row_ind, col_ind): + pairs.append((points1[i], points2[j])) + + return pairs + + +def interpolate_point_pairs(pairs, percentage): + interpolated_points = [] + for pair in pairs: + point1, point2 = pair + interpolated_point = point1.interpolate(point2, percentage) + interpolated_points.append(interpolated_point) + return interpolated_points + + +Image1 = Image.open("CiscoTheProot/faces/prootface3.png") +Image2 = Image.open("CiscoTheProot/faces/prootface4.png") + +pixelArray1 = generate_point_array_from_image(Image1) +pixelArray2 = generate_point_array_from_image(Image2) + +pairs = pair_points(pixelArray1, pixelArray2) + + +generate_image_from_point_array(interpolate_point_pairs(pairs, 0), 128, 32).show() +generate_image_from_point_array(interpolate_point_pairs(pairs, .25), 128, 32).show() +generate_image_from_point_array(interpolate_point_pairs(pairs, .5), 128, 32).show() +generate_image_from_point_array(interpolate_point_pairs(pairs, .75), 128, 32).show() +generate_image_from_point_array(interpolate_point_pairs(pairs, 1), 128, 32).show() + +print(pairs) \ No newline at end of file diff --git a/rpi/antRender.py b/rpi/antRender.py new file mode 100644 index 0000000..873b187 --- /dev/null +++ b/rpi/antRender.py @@ -0,0 +1,222 @@ +from rgbmatrix import RGBMatrix, RGBMatrixOptions +import paho.mqtt.client as mqtt +import time +from PIL import Image +import numpy as np + + +# Configuration for the matrix +options = RGBMatrixOptions() +options.rows = 32 +options.cols = 64 +options.chain_length = 2 +options.parallel = 1 +options.hardware_mapping = 'regular' # If you have an Adafruit HAT: 'adafruit-hat' +matrix = RGBMatrix(options=options) + + +import math +from PIL import Image +import numpy as np +from scipy.optimize import linear_sum_assignment + + +class Point2D: + x = 0 + y = 0 + + def __init__(self, x, y): + self.x = x + self.y = y + + def round(self): + self.x = round(self.x) + self.y = round(self.y) + return self + + def distance(self, other): + dx = self.x - other.x + dy = self.y - other.y + return math.sqrt(dx**2 + dy**2) + + def interpolate(self, other, percentage): + new_x = self.x + (other.x - self.x) * percentage + new_y = self.y + (other.y - self.y) * percentage + return Point2D(new_x, new_y) + + def __eq__(self, other): + return (self.x, self.y) == (other.x, other.y) + + +def generate_point_array_from_image(image): + image = image.convert("RGB") # Convert image to RGB color mode + + width, height = image.size + point_array = [] + + # Iterate over the pixels and generate Point2D instances + for y in range(height): + for x in range(width): + pixel = image.getpixel((x, y)) + if pixel != (0, 0, 0): # Assuming white pixels + point = Point2D(x, y) + point_array.append(point) + + return point_array + + +def generate_image_from_point_array(points, width, height): + # Create a new blank image + image = Image.new("RGB", (width, height), "black") + + # Set the pixels corresponding to the points as white + pixels = image.load() + for point in points: + point = point.round() + x = point.x + y = point.y + pixels[x, y] = (255, 255, 255) + + return image + + +def pair_points(points1, points2): + # Determine the size of the point arrays + size1 = len(points1) + size2 = len(points2) + + # Create a cost matrix based on the distances between points + cost_matrix = np.zeros((size1, size2)) + for i in range(size1): + for j in range(size2): + cost_matrix[i, j] = points1[i].distance(points2[j]) + + # Duplicate points in the smaller array to match the size of the larger array + if size1 > size2: + num_duplicates = size1 - size2 + duplicated_points = np.random.choice(points2, size=num_duplicates).tolist() + points2 += duplicated_points + elif size2 > size1: + num_duplicates = size2 - size1 + duplicated_points = np.random.choice(points1, size=num_duplicates).tolist() + points1 += duplicated_points + + # Update the size of the point arrays + size1 = len(points1) + size2 = len(points2) + + # Create a new cost matrix with the updated sizes + cost_matrix = np.zeros((size1, size2)) + for i in range(size1): + for j in range(size2): + cost_matrix[i, j] = points1[i].distance(points2[j]) + + # Solve the assignment problem using the Hungarian algorithm + row_ind, col_ind = linear_sum_assignment(cost_matrix) + + # Create pairs of points based on the optimal assignment + pairs = [] + for i, j in zip(row_ind, col_ind): + pairs.append((points1[i], points2[j])) + + return pairs + + +def interpolate_point_pairs(pairs, percentage): + interpolated_points = [] + for pair in pairs: + point1, point2 = pair + interpolated_point = point1.interpolate(point2, percentage) + interpolated_points.append(interpolated_point) + return interpolated_points + + +Image1 = Image.open("faces/prootface3.png") +Image2 = Image.open("faces/prootface4.png") + +pixelArray1 = generate_point_array_from_image(Image1) +pixelArray2 = generate_point_array_from_image(Image2) + +pairs = pair_points(pixelArray1, pixelArray2) + + + + + + +DesiredBlinkState = 10 +currentBlinkState = 0 + +blinkFrameCanvases = [] + +offscreen_interpolated_canvasA = matrix.CreateFrameCanvas() +offscreen_interpolated_canvasA.brightness = 50 +offscreen_interpolated_canvasA.SetImage(generate_image_from_point_array(interpolate_point_pairs(pairs, 0), 128, 32), unsafe=False) +blinkFrameCanvases.append(offscreen_interpolated_canvasA) + +for alpha in range(1,10): + offscreen_interpolated_canvas = matrix.CreateFrameCanvas() + interpolated_image = generate_image_from_point_array(interpolate_point_pairs(pairs, alpha), 128, 32) + offscreen_interpolated_canvas.SetImage(interpolated_image, unsafe=False) + blinkFrameCanvases.append(offscreen_interpolated_canvas) + +offscreen_interpolated_canvasB = matrix.CreateFrameCanvas() +offscreen_interpolated_canvasB.SetImage(generate_image_from_point_array(interpolate_point_pairs(pairs, 1), 128, 32), unsafe=False) +blinkFrameCanvases.append(offscreen_interpolated_canvasB) + + + +def update_screen(): + global DesiredBlinkState, currentBlinkState, blinkFrameCanvases, matrix, offscreen_interpolated_canvasA + + # open eye again after blink + if currentBlinkState == 10: + DesiredBlinkState = 0 + + if currentBlinkState == DesiredBlinkState: + next_canvas = blinkFrameCanvases[currentBlinkState] + return + + + next_canvas = blinkFrameCanvases[currentBlinkState] + + if currentBlinkState < DesiredBlinkState: + currentBlinkState += 1 + else: + currentBlinkState -= 1 + + next_canvas = matrix.SwapOnVSync(next_canvas) + + + + +# functions called by the MQTT listener +def on_connect(client, userdata, flags, response_code): + print("Connected to MQTT broker with result code " + str(response_code)) + client.subscribe("test") + + +def on_message(client, userdata, message): + print("Received message '" + str(message.payload) + "' on topic '" + + message.topic + "' with QoS " + str(message.qos)) + global DesiredBlinkState + DesiredBlinkState = 10 + +# MQTT broker configuration +broker_address = "10.1.13.173" # Replace with your MQTT broker's address +broker_port = 1883 +broker_keepalive = 60 + +client = mqtt.Client() +client.on_connect = on_connect +client.on_message = on_message + +client.connect(broker_address, broker_port, broker_keepalive) + +client.loop_start() + + +while True: + time.sleep(0.05) + update_screen() + \ No newline at end of file diff --git a/testImg1.png b/testImg1.png new file mode 100644 index 0000000..b9b6021 Binary files /dev/null and b/testImg1.png differ diff --git a/testImg2.png b/testImg2.png new file mode 100644 index 0000000..426285b Binary files /dev/null and b/testImg2.png differ