aboutsummaryrefslogtreecommitdiff
path: root/Arduino/sensor/sensor.ino
diff options
context:
space:
mode:
Diffstat (limited to 'Arduino/sensor/sensor.ino')
-rw-r--r--Arduino/sensor/sensor.ino215
1 files changed, 215 insertions, 0 deletions
diff --git a/Arduino/sensor/sensor.ino b/Arduino/sensor/sensor.ino
new file mode 100644
index 0000000..8d43b22
--- /dev/null
+++ b/Arduino/sensor/sensor.ino
@@ -0,0 +1,215 @@
+// SPDX-FileCopyrightText: 2025 Amal Mazrah <mazrah@ruc.dk>
+// SPDX-FileCopyrightText: 2025 Jonas Smedegaard <dr@jones.dk>
+// SPDX-FileCopyrightText: 2025 Mennatullah Hatim Kassim <stud-mennatulla@ruc.dk>
+// SPDX-FileCopyrightText: 2025 Noor Ahmad <noora@ruc.dk>
+// SPDX-FileCopyrightText: 2025 Tanishka Suwalka <tanishkas@ruc.dk>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+/// Sensor mussel - an Arduino sketch to emulate a mussel biosensor
+///
+/// @version 0.0.3
+/// @see <https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z2tFBF4gN7ziG9oXtUytVQNYe3VhQ>
+/// @see <https://moodle.ruc.dk/course/view.php?id=23504>
+
+// arduino-esp32 Logging system
+// activate in Arduino IDE: Tools -> Core Debug Level
+// special: set Core Debug Level to Error for plot-friendly output
+#define CONFIG_ARDUHAL_ESP_LOG 1
+#define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
+#include <esp32-hal-log.h>
+#undef ARDUHAL_LOG_FORMAT
+#define ARDUHAL_LOG_FORMAT(letter, format) \
+ ARDUHAL_LOG_COLOR_##letter "[" #letter "] %s(): " format \
+ ARDUHAL_LOG_RESET_COLOR "\r\n", __FUNCTION__
+
+// arduino-esp32 Bluetooth Low Energy (BLE) networking stack
+#include "BLEDevice.h"
+#include "BLEBeacon.h"
+#include "BLEAdvertising.h"
+#include "BLEEddystoneTLM.h"
+
+// Adjust these for production use
+//
+// * BEACON_NAME must be unique within deployment
+// * BEACON_UUID should be unique for each deployment
+//
+// @see https://www.uuidgenerator.net/
+#define BEACON_NAME "Dummy mussel sensor"
+#define BEACON_UUID "00000000-0000-0000-0000-000000000000"
+
+// maximum accumulated stress
+#define STRESS_MAX 50
+
+// light sensor
+#define LIGHT_PIN 34
+#define DARKNESS_MAX 1000
+
+// arduino-esp32 Touch sensor
+#define TOUCH_PIN T0 // T0 is GPIO4
+#define TOUCH_THRESHOLD 40
+
+// arduino-esp32 LED PWM Controller (LEDC) as pacemaker for gaping rhythm
+#define LED_PIN LED_BUILTIN
+#define LEDC_BITS 7
+#define LEDC_FREQ 500
+#define LEDC_START_DUTY 0
+#define LEDC_TARGET_DUTY 90
+#define LEDC_CALM_PACE 3000
+#define LEDC_STRESSED_PACE 400
+
+// pacemaker variables
+int stress = 0;
+bool touch_detected = false;
+int pace = LEDC_STRESSED_PACE;
+bool fade_ended = false;
+bool fade_in = true;
+
+// pointer to control Bluetooth networking
+BLEAdvertising *pAdvertising;
+
+// Touch sensor callback
+void gotTouch() {
+// keepPace();
+ touch_detected = true;
+ pace = LEDC_STRESSED_PACE;
+}
+
+// pacemaker end-of-fade Interrupt Service Routine (ISR) a.k.a. callback
+void ARDUINO_ISR_ATTR LED_FADE_ISR() {
+ fade_ended = true;
+ keepPace();
+}
+
+// stress-inducing touch callback
+void beginTouchDetection() {
+ touchAttachInterrupt(TOUCH_PIN, gotTouch, TOUCH_THRESHOLD);
+ log_d("touch detected");
+}
+
+// pacemaker initialization
+void beginPace() {
+
+ // Setup pacemaker timer
+ ledcAttach(LED_PIN, LEDC_FREQ, LEDC_BITS);
+
+ // fade in once uncontrolled and then begin fade out with ISR
+ ledcFade(LED_PIN, LEDC_START_DUTY, LEDC_TARGET_DUTY, pace);
+ delay(pace);
+ ledcFadeWithInterrupt(LED_PIN, LEDC_TARGET_DUTY, LEDC_START_DUTY,
+ pace, LED_FADE_ISR);
+}
+
+// pacemaker maintenance
+void keepPace() {
+
+// if (fade_ended || touch_detected) {
+ if (fade_ended) {
+ fade_ended = false;
+
+ // stress management
+ if (touch_detected) {
+ touch_detected = false;
+ log_i("Stressed by touch!");
+ if (stress < STRESS_MAX) {
+ stress = stress + 10;
+ }
+ } else if (stress > 0) {
+ stress--;
+ if (stress <= 0) {
+ pace = LEDC_CALM_PACE;
+ log_i("Calmed down...");
+ } else {
+ log_i("Still stressed...");
+ }
+ } else {
+ pace = LEDC_CALM_PACE;
+ }
+
+ // begin fade at decided direction and pace
+ ledcFadeWithInterrupt(LED_PIN,
+ fade_in ? LEDC_START_DUTY : LEDC_TARGET_DUTY,
+ fade_in ? LEDC_TARGET_DUTY : LEDC_START_DUTY,
+ pace, LED_FADE_ISR);
+
+ // remember next fade direction
+ fade_in = !fade_in;
+ }
+}
+
+// read light intensity and return its non-zero capped value
+int getLightIntensity() {
+ int value = analogRead(LIGHT_PIN);
+ if (value > DARKNESS_MAX)
+ value = DARKNESS_MAX;
+ log_i("light intensity: %d", value);
+
+ return DARKNESS_MAX - value;
+}
+
+// fake gape angle as pacemaker position dampened by light intensity
+int resolveGapeAngle() {
+ int paceAngle = ledcRead(LED_PIN);
+ log_i("pacemaker value: %d", value);
+
+ int lightIntensity = getLightIntensity();
+ log_i("light intensity: %d", value);
+
+ int gapeAngle = paceAngle * lightIntensity / DARKNESS_MAX;
+
+ // misuse error-only log level for plot-friendly output
+#if ARDUHAL_LOG_LEVEL == ARDUHAL_LOG_LEVEL_ERROR
+ Serial.printf("pace_angle:%d light/10:%d gape_angle:%d\n",
+ paceAngle, lightIntensity/10, gapeAngle);
+#endif
+
+ return gapeAngle;
+}
+
+// Encode static Bluetooth beacon advertisement data
+void setBeaconAdvertisement() {
+ BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
+ oAdvertisementData.setName(BEACON_NAME);
+ pAdvertising->setAdvertisementData(oAdvertisementData);
+}
+
+// Encode variable Bluetooth beacon service data
+void setBeaconServiceData(int angle) {
+ BLEEddystoneTLM EddystoneTLM;
+ EddystoneTLM.setTemp(angle);
+ log_i("Gape angle: %.2f°", EddystoneTLM.getTemp());
+
+ BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
+ oScanResponseData.setServiceData(
+ BLEUUID((uint16_t)0xFEAA),
+ String(
+ EddystoneTLM.getData().c_str(),
+ EddystoneTLM.getData().length()));
+ pAdvertising->setScanResponseData(oScanResponseData);
+}
+
+void setup() {
+
+ // enable logging to serial
+ Serial.begin(115200);
+ esp_log_level_set("*", ESP_LOG_DEBUG);
+ if (BEACON_UUID == "00000000-0000-0000-0000-000000000000")
+ Serial.println("Please set a deployment-wide unique BEACON_UUID");
+
+ beginPace();
+ beginTouchDetection();
+
+ // setup Bluetooth
+ BLEDevice::init(BEACON_NAME);
+ pAdvertising = BLEDevice::getAdvertising();
+ setBeaconAdvertisement();
+ setBeaconServiceData(resolveGapeAngle());
+ pAdvertising->start();
+}
+
+void loop() {
+
+ // update Bluetooth beacon service data
+ setBeaconServiceData(resolveGapeAngle());
+
+ delay(500);
+}