From 44eb955b9f6fd558f930b319db17f54132df5429 Mon Sep 17 00:00:00 2001 From: Dooho Yi Date: Tue, 13 Oct 2026 17:02:58 +0900 Subject: [PATCH] a 'chime' autonomouse? --- faa_chime/faa_chime.ino | 348 ++++++++++++++++++++++++++++++++++++++++ faa_chime/message.h | 111 +++++++++++++ faa_chime/sketch.yaml | 2 + 3 files changed, 461 insertions(+) create mode 100644 faa_chime/faa_chime.ino create mode 100644 faa_chime/message.h create mode 100644 faa_chime/sketch.yaml diff --git a/faa_chime/faa_chime.ino b/faa_chime/faa_chime.ino new file mode 100644 index 0000000..7da63f9 --- /dev/null +++ b/faa_chime/faa_chime.ino @@ -0,0 +1,348 @@ +// +// wirelessly connected cloud or crowd +// over WIFI over Internet over Mountains +// across Rivers and the Universe +// + +// +// tailored for "Saekki-Chigi4" +// 2026 04 13 - Seoul +// + +// +// NOTES +// + +// ** IDENTITY ** +#define MY_SPECIES ("CHIME") +#define MY_NAME ("CHIMEE {a.k.a. chime1}") + +//arduino +#include + +//wifi manager +#include + +//osc over UDP +#include +#include +#include +#include +#include +// +WiFiUDP Udp; +// +const IPAddress outIp(192,168,199,179); // server ip +const unsigned int outPort = 9999; // server port +const unsigned int localPort = 8888; // my port opened (<== expecting connection) +OSCErrorCode error; + +//task +#include +Scheduler runner; + +//-*-*-*-*-*-*-*-*-*-*-*-*- +// servo +#define MOTOR_1A (D6) +#define MOTOR_1B (D5) +int speed = 0; +bool isactive = false; +void set_speed() { + int r = speed; + // + if (r >= 0) { + digitalWrite(MOTOR_1A, LOW); + analogWrite(MOTOR_1B, r); + } else { + digitalWrite(MOTOR_1B, LOW); + analogWrite(MOTOR_1A, r*(-1)); + } + // Serial.print("set_speed:"); + // Serial.println(r); + isactive = true; +} +Task set_speed_task(0, TASK_ONCE, &set_speed, &runner, false); +// +void rest() { + analogWrite(MOTOR_1A, LOW); + analogWrite(MOTOR_1B, LOW); + isactive = false; +} +Task rest_task(0, TASK_ONCE, &rest, &runner, false); +// +#define MOTOR_2A (D3) +#define MOTOR_2B (D2) +int speed2 = 0; +void set_speed2() { + int r = speed2; + // + if (r >= 0) { + digitalWrite(MOTOR_2A, LOW); + analogWrite(MOTOR_2B, r); + } else { + digitalWrite(MOTOR_2B, LOW); + analogWrite(MOTOR_2A, r*(-1)); + } + // Serial.print("set_speed2:"); + // Serial.println(r); +} +Task set_speed2_task(0, TASK_ONCE, &set_speed2, &runner, false); +// +void rest2() { + analogWrite(MOTOR_2A, LOW); + analogWrite(MOTOR_2B, LOW); +} +Task rest2_task(0, TASK_ONCE, &rest2, &runner, false); +//*-*-*-*-*-*-*-*-*-*-*-*-* + +//*-*-*-*-*-*-*-*-*-*-*-*-* +//expressions +//riff_A +std::vector< std::vector > chimeA = { + {0.4,0.133332,-0.409527,0.142857,-0.46667,0.619048,0.104762,-0.495242,-0.361908,0.466668}, + //10 + + {0.809524,0.809524,0.819048,0.819048,0.819048,0.809524,0.7,0.695239,0.695239,0.695239,0.695239,0.438095,0.695239,0.690477,0.685715,0.447619,0.680952,0.680952,0.680952,0.680952,0.680952,0.82381,0.82381,0.666666,0.666666,0.671429,0.671429,0.814286,0.814286,0.657142,0.657142,0.657142,0.642856,0.623807,0.623807,0.623807,0.809524,0.361905,0.809524,0.361905,0.714285,0.714285,0.723809,0.761905,0.761905,0.771429,0.771429,0.771429,0.771429,0.800001} + //50 +}; +// +extern Task riff_A_task; +int wordA = 0; +float rateA = 900.0; // * 900 (scaling factor) +float intervalA = 2000.0; //2000 ms +void riff_A() { + //check out next letter! (==value) + speed = chimeA[wordA][riff_A_task.getRunCounter()-1] * rateA; + set_speed_task.restart(); + + //info + Serial.print("riff_A (i="); + Serial.print(riff_A_task.getRunCounter()-1); + Serial.print(", r="); + Serial.print(speed); + Serial.println(")"); + + //if we are done... schedule a 'rest_task' + if (riff_A_task.isLastIteration()) { + rest_task.restartDelayed(intervalA + 100); + } +} +Task riff_A_task(0, TASK_ONCE, &riff_A, &runner, false); +// +void riff_A_start() { + riff_A_task.setInterval(intervalA); + riff_A_task.setIterations(chimeA[wordA].size()); + riff_A_task.restart(); + // + Serial.print("riff_A_start with wordA #"); + Serial.println(wordA); +} +Task riff_A_start_task(0, TASK_ONCE, &riff_A_start, &runner, false); +// +//riff_B +std::vector< std::vector > chimeB = { + {0.4,0.133332,-0.409527,0.142857,-0.46667,0.619048,0.104762,-0.495242,-0.361908,0.466668}, + //10 + + {0.809524,0.809524,0.819048,0.819048,0.819048,0.809524,0.7,0.695239,0.695239,0.695239,0.695239,0.438095,0.695239,0.690477,0.685715,0.447619,0.680952,0.680952,0.680952,0.680952,0.680952,0.82381,0.82381,0.666666,0.666666,0.671429,0.671429,0.814286,0.814286,0.657142,0.657142,0.657142,0.642856,0.623807,0.623807,0.623807,0.809524,0.361905,0.809524,0.361905,0.714285,0.714285,0.723809,0.761905,0.761905,0.771429,0.771429,0.771429,0.771429,0.800001} + //50 +}; +// +extern Task riff_B_task; +int wordB = 0; +float rateB = 900.0; // * 900 (scaling factor) +float intervalB = 2000.0; //2000 ms +void riff_B() { + //check out next letter! + speed2 = chimeB[wordB][riff_B_task.getRunCounter()-1] * rateB; + set_speed2_task.restart(); + + //info + Serial.print("riff_B (i="); + Serial.print(riff_B_task.getRunCounter()-1); + Serial.print(", r="); + Serial.print(speed2); + Serial.println(")"); + + //if we are done... schedule a 'rest_task' + if (riff_B_task.isLastIteration()) { + rest2_task.restartDelayed(intervalB + 100); + } +} +Task riff_B_task(0, TASK_ONCE, &riff_B, &runner, false); +// +void riff_B_start() { + riff_B_task.setInterval(intervalB); + riff_B_task.setIterations(chimeB[wordB].size()); + riff_B_task.restart(); + // + Serial.print("riff_B_start with wordB #"); + Serial.println(wordB); +} +Task riff_B_start_task(0, TASK_ONCE, &riff_B_start, &runner, false); +//*-*-*-*-*-*-*-*-*-*-*-*-* + +//*-*-*-*-*-*-*-*-*-*-*-*-* +// conductor for today (temporary conductor until wifi enabled.) +// +extern Task conductor_lonely_task; +float lonelytime = 5000; //ms +void conductor_lonely() { + // + static int count = 0; + if (count == chimeA.size()) count = 0; + // + if (isactive == false) { // if no more movement, then start another lonely song. + // + isactive = true; + // + lonelytime = random(3, 10) * 10000.0; //ms + // + wordA = count; + riff_A_start_task.restartDelayed(lonelytime); + wordB = count; + riff_B_start_task.restartDelayed(lonelytime); + // + Serial.print("conductor_lonely with lonelytime => "); + Serial.println(lonelytime); + Serial.print("conductor_lonely with count #"); + Serial.println(count); + // + count++; + } +} +Task conductor_lonely_task(1000, TASK_FOREVER, &conductor_lonely, &runner, false); +//*-*-*-*-*-*-*-*-*-*-*-*-* + +// ==[DISABLE]== +// //task #0 : blink led +// #define LED_PERIOD (11111) +// #define LED_ONTIME (1) +// #define LED_GAPTIME (222) +// #define LED_PIN 2 +// extern Task blink_task; +// void blink() { +// // +// static int count = 0; +// count++; +// // +// switch (count % 4) { +// case 0: +// digitalWrite(LED_PIN, LOW); // first ON +// blink_task.delay(LED_ONTIME); +// break; +// case 1: +// digitalWrite(LED_PIN, HIGH); // first OFF +// blink_task.delay(LED_GAPTIME); +// break; +// case 2: +// digitalWrite(LED_PIN, LOW); // second ON +// blink_task.delay(LED_ONTIME); +// break; +// case 3: +// digitalWrite(LED_PIN, HIGH); // second OFF +// blink_task.delay(LED_PERIOD - 2* LED_ONTIME - LED_GAPTIME); +// break; +// } +// } +// Task blink_task(0, TASK_FOREVER, &blink, &runner, true); // -> ENABLED, at start-up. + +//task #1 : osc processing +void route_note(OSCMessage& msg, int offset) { + if (msg.fullMatch("/word", offset)) { + wordA = msg.getFloat(0); + wordB = msg.getFloat(0); + riff_A_start_task.restartDelayed(100); + riff_B_start_task.restartDelayed(100); + // + Serial.print("OSC: /word : "); + Serial.print(wordA); + Serial.print(", "); + Serial.println(wordB); + } +} +extern Task osc_task; +void osc() +{ + //osc + OSCMessage msg; + int size = Udp.parsePacket(); + if (size > 0) { + while (size--) { + msg.fill(Udp.read()); + } + if(!msg.hasError()) { + // on '/yellow' + msg.route("/yellow", route_note); + Serial.println("OSC: /yellow"); + } + } +} +Task osc_task(0, TASK_FOREVER, &osc, &runner, true); // -> ENABLED, at start-up. + +// +void setup() { + + //led + // pinMode(LED_PIN, OUTPUT); + + //pwm freq. + analogWriteFreq(40000); + + //serial + Serial.begin(115200); + delay(100); + + //info + Serial.println(); + Serial.println(); + Serial.println("\"hi, i m your friend.\""); + Serial.println("-"); + Serial.println("- my species: \"" + String(MY_SPECIES) + "\""); + Serial.println("- call me ==> \"" + String(MY_NAME) + "\""); + Serial.println("- mac address: " + WiFi.macAddress()); + Serial.println("-"); + + // //wifi-manager + // Serial.println("- calling.. wifimanager"); + // WiFiManager wm; + // if (!wm.autoConnect()) ESP.restart(); + // Serial.println("- i m connected!"); + + //open up udp connection + Serial.println("- IP address: "); + Serial.println(WiFi.localIP()); + Serial.println("- Starting UDP"); + Udp.begin(localPort); + Serial.print("- Local port: "); + Serial.println(Udp.localPort()); + + //all done. + Serial.println("-"); + Serial.println("\".-.-.-. :)\""); + Serial.println(); + + //random seed + randomSeed(analogRead(0)); + + //tasks + rest_task.restartDelayed(500); + rest2_task.restartDelayed(500); + + wordA = 0; + riff_A_start_task.restartDelayed(1000); + wordB = 0; + riff_B_start_task.restartDelayed(1000); + + conductor_lonely_task.restartDelayed(5000); + // + // for (int idx = 0; idx < chimeA.size(); idx++) Serial.println(chimeA[idx].size()); + // for (int idx = 0; idx < chimeB.size(); idx++) Serial.println(chimeB[idx].size()); + // +} + +void loop() { + // + runner.execute(); + // +} diff --git a/faa_chime/message.h b/faa_chime/message.h new file mode 100644 index 0000000..8e2b9ab --- /dev/null +++ b/faa_chime/message.h @@ -0,0 +1,111 @@ +#pragma once + +//message type Note : '[' + Note + ']' +struct Note { + // + int32_t id; + float pitch; + float velocity; + float onoff; + float x1; + float x2; + float x3; + float x4; + float ps; + // + Note() { + id = 0; + pitch = 0; + velocity = 0; + onoff = 0; + x1 = 0; + x2 = 0; + x3 = 0; + x4 = 0; + ps = 0; + } + Note(int32_t id_, float pitch_, float velocity_, float onoff_, float x1_, float x2_, float x3_, float x4_, float ps_) + { + id = id_; + pitch = pitch_; + velocity = velocity_; + onoff = onoff_; + x1 = x1_; + x2 = x2_; + x3 = x3_; + x4 = x4_; + ps = ps_; + } + // + void clear() { + id = 0; + pitch = 0; + velocity = 0; + onoff = 0; + x1 = 0; + x2 = 0; + x3 = 0; + x4 = 0; + ps = 0; + } + // + String to_string() { + String str = ""; + str += "( id=" + String(id); + str += ", pitch=" + String(pitch); + str += ", velocity=" + String(velocity); + str += ", onoff=" + String(onoff); + str += ", x1=" + String(x1); + str += ", x2=" + String(x2); + str += ", x3=" + String(x3); + str += ", x4=" + String(x4); + str += ", ps=" + String(ps); + str += " )"; + return str; + } +}; + +//message type Hello : '{' + Hello + '}' +#define SIGNATURE_LENGTH (20) +#define SIGNATURE_BUFF_LEN (SIGNATURE_LENGTH + 1) +struct Hello { + char sign[SIGNATURE_BUFF_LEN]; + int32_t id; + uint32_t mac32; + float h1; + float h2; + float h3; + float h4; + // + Hello(String sign_, int32_t id_ = 0, uint32_t mac32_ = 0, float h1_ = 0, float h2_ = 0, float h3_ = 0, float h4_ = 0) { + id = id_; + mac32 = mac32_; + h1 = h1_; + h2 = h2_; + h3 = h3_; + h4 = h4_; + sign_.toCharArray(sign, SIGNATURE_BUFF_LEN); + } + void clear() { + id = 0; + mac32 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + sign[0] = '\0'; + } + // + String to_string() { + String str = ""; + str += "( id=" + String(id); + str += ", mac32=0x" + String(mac32, HEX); + str += ", sign=\"" + String(sign) + "\""; + str += ", h1=" + String(h1); + str += ", h2=" + String(h2); + str += ", h3=" + String(h3); + str += ", h4=" + String(h4); + str += " )"; + return str; + } +}; diff --git a/faa_chime/sketch.yaml b/faa_chime/sketch.yaml new file mode 100644 index 0000000..35e1831 --- /dev/null +++ b/faa_chime/sketch.yaml @@ -0,0 +1,2 @@ +default_fqbn: esp8266:esp8266:nodemcuv2:baud=460800 +default_port: /dev/ttyUSB0