diff --git a/2022-11-30_scenarij.txt b/2022-11-30_scenarij.txt deleted file mode 100644 index 388c5f2..0000000 --- a/2022-11-30_scenarij.txt +++ /dev/null @@ -1,28 +0,0 @@ -1. en kegel - samo deformacija, mogoce malo zoom - pulz na zogico, - + nojz (glasba, rocno?) - - BREZ zogic - - BREZ dodatnih -2. dva kegla -3. ena zogica -4. 2 kegla + zogica - -===== VKLOP LUCI ====== - -reset (calibrate, zoom blizu) - (nojz stran) - (vklopimo zogice) - -5. komad: ena zogica! -6. tri zogice - -7. band: vkljucimo publiko - + VKLOP dodatni kegli - -TODO: -- barvne palete za zogice (izmenicno levo desno), kegle -- upostevaj velocity zogic -- WW kontroler za vklop / izklop deformacije, ostalih elementov (barva ja / ne) -- postavit kegle v sredino -- postavit zogice v kader diff --git a/README.md b/README.md deleted file mode 100644 index ebc33de..0000000 --- a/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Glasbena miza - -Ta zbirka vsebuje kodo, s pomočjo katere lahko kegle spremenimo v inštrumente. To dosežemo z vgradnjo ESP32 mikrokrmilnikov in MPU9255 gibalnih senzorjev. - -## Mere - -Najdaljši premer - 82mm -Špica - 15mm -32mm je lahko dolg vstavek -27mm je široka spodnja odprtina (blizu držalu) - -Zapečemo ga s strani (izrez + prispajk nazaj) - -## Kako? - - - -## Razno - -Problem s flashanjem: - -``` -esp_core_dump_flash: Core dump flash config is corrupted! CRC=0x7bd5c66f instead of 0x0 -``` - -V arduino IDE nastaviš `Flash mode` na "DIO" namesto "QIO". diff --git a/README.org b/README.org new file mode 100644 index 0000000..33fd977 --- /dev/null +++ b/README.org @@ -0,0 +1,122 @@ +#+TITLE: kiber kegel + +* Splošno + +Kiber kegli so del [[https://mismonismo.org/shows/music-table-glasbena-miza/][glasbene mize]]. + +Ta zbirka kode vsebuje načrte, dokumentacijo in kodo za nadgradnjo keglov v glasbene inštrumente. Preko brezžičnega mikrokrmilnika (ESP32) pošiljajo spremembe rotacij in pospeškov gibalnega senzorja (MPU9255) v računalnik, ki podatke v obliki OSC pretvori v MIDI signale. + +* Strojni del - telo +** Mere kegla + +Najdaljši premer - 82mm +Špica - 15mm +32mm je lahko dolg vstavek +27mm je široka spodnja odprtina (blizu držalu) + +Zapečemo ga s strani (izrez + prispajk nazaj). Kasneje sva se raje odločila za vijake, tako je kegel lažje popravljat. + +[[file:2022-11-27_kegel.jpg][prototip kegla]] + +[[file:slike/IMG_20230618_131926.jpg][Narejen kegel spredaj]] + +[[file:slike/IMG_20230618_131933.jpg][Narejen kegel zadaj]] + +** Elektonske povezave + +| MPU9255 | ESP32 | +|---------+-------| +| VCC | 3.3v | +| GND | GND | +| SCL | 22 | +| SDA | 21 | + +Baterijski priklop omogoča [[https://docs.wemos.cc/en/latest/d1_mini_shield/battery.html][baterijski shield]] za [[https://docs.wemos.cc/en/latest/d1/index.html][wemos d1 mini]] (esp32 varjanta). Lahko bi imeli tudi kakšno esp32 krmilnik z vgrajenim regulatorjem napetosti in priklopom na baterijo. + +Ena žica baterije (+ pol?) je vezana preko stikala, speljanega na rob kegla, da ga je mogoče ugansniti. ~POZOR~ pri priklopu baterije na baterijski shield moramo pazit na polariteto; barve baterijskih kablov se ne skladajo nujno s +/- poli na shieldu, napačen priklop lahko skuri tuljavo. + +[[file:slike/IMG_20230618_131305.jpg][Kegel znotraj]] + +USB priklop baterijskega shielda je speljan za rob kegla za lažje polnjenje preko robustnejšega vtikača USB tipa B. + +[[file:slike/IMG_20230618_130022.jpg][Kegel znotraj 2]] + +Sprva je za brezžični prenos podatkov skrbel bluetooth protokol. Kasneje se je pa izkazalo da je precej lažje uporabit ESP-NOW preko še enega krmilnik za sprejem. Tako je lažje in hitreje vzpostavit povezavo s kegli, prenos je konsistentnejši, doseg bi moral biti večji (tukaj je sicer bluetooth bil dovolj dober). + +S pomočjo [[https://github.com/thomasfla/Linux-ESPNOW][tega projekta]] bi moralo biti mogoče prejemati ESPNOW pakete brez dodatnega sprejemnika. + +TODO slika sprejemnika. + +* Koda + +Poganjanje projekta omogoča tudi koda, ki se nahaja na več mestih; arduino koda za krmilnik je tako v keglu kot v sprejemniku, potem imamo pretvornik brezžično prejetih signalov v midi (neposredno oz. pretvorjeno). Opcionalno tudi vizualiziramo zadevo. + +** Krmilnik v keglu + +Krmilnik v keglu, ki prebira senzorje in pošilja podatke v sprejemnik, je spisan [[file:osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.org][v tej skici]]. Preden skico zapečemo na kegel, je potrebno kalibrirati magnetometer. + +*** Kalibracija +Magnetometerski senzor je potrebo kalibrirati, skica za kalibracijo je [[file:ArduinoMagCal/ArduinoMagCal.ino][tukaj]]. Skico zapečemo na krmilnik in sledimo navodilom na serijskem monitorju. + +** Sprejemni krmilnik + +Skica za brezžični sprejemnik je [[file:osc32_espnow_sprejemnik/osc32_espnow_sprejemnik.ino][tukaj]]. Z nekaj prilagoditvami lahko namesto ~ESP32~ uporabimo tudi ~ESP8266~, ki prav tako podpira ~ESP-NOW~ protokol. +TODO literate programming! + +** Pretvornik iz serijskega OSC v midi + + - wavey wind TODO + - pretvornik TODO + +* Scenariji +** 30. 11. 2022 (cirkulacija) +1. en kegel + samo deformacija, mogoce malo zoom + pulz na zogico, + + nojz (glasba, rocno?) + + BREZ zogic + + BREZ dodatnih +2. dva kegla +3. ena zogica +4. 2 kegla + zogica + +===== VKLOP LUCI ====== + +reset (calibrate, zoom blizu) + (nojz stran) + (vklopimo zogice) + +5. komad: ena zogica! +6. tri zogice + +7. band: vkljucimo publiko + + VKLOP dodatni kegli + +TODO: +- barvne palete za zogice (izmenicno levo desno), kegle +- upostevaj velocity zogic +- WW kontroler za vklop / izklop deformacije, ostalih elementov (barva ja / ne) +- postavit kegle v sredino +- postavit zogice v kader + +* Ideje za naprej +** sprejemnik → bitwig +Namesto pretvorne komponente iz serijskega OSC v midi bi lahko bitwig neposredno prejemal podatke iz sprejemnika. [[https://github.com/Dewb/bitwig-serialosc-example][Tale primer]] skripte za bitwig izgleda dokaj podoben željenemu in bi z nekaj prilagoditvami verjetno lahko vskočil. Slaba stran je specifičnost bitwigu + +** supercollider sprejemnik +Pretvorbo iz serijskega OSC v midi bi lahko implementirali v supercolliderju. [[https://github.com/madamdata/SLIPDecoder][Tale quark]] dela podobno stvar, v delu imam generalizacijo. Supercollider je nekoliko lažje namestit kot javascript, precej bolj prijeten je za eksperimentacijo. Enostavno bi bilo narediti preprost GUI v njem. + +* Težave + +** počasno/redko pošiljanje podatkov + +Če se gibalni podatki pri napajanju iz baterije zelo počasi pošiljajo, pri povezavi preko USB kabla pa kegel deluje pravilno, je verjetno baterija prazna in jo je treba napolnit. + +** problem pri nalaganju firmware-a + +#+begin_quote +esp_core_dump_flash: Core dump flash config is corrupted! CRC=0x7bd5c66f instead of 0x0 +#+end_quote + +V arduino IDE nastaviš ~Flash mode~ na ~DIO~ namesto ~QIO~. + diff --git a/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.ino b/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.ino index b8e03e0..120229d 100644 --- a/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.ino +++ b/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.ino @@ -1,10 +1,9 @@ // ESP32 Dev Module -#include - // ID kegla mora bit unikaten za vsakega! (se poslje poleg parametrov) #define KEGEL_ID 1 +#include // IMU libraries #include "I2Cdev.h" #include "RTIMUSettings.h" @@ -13,9 +12,6 @@ #include "CalLib.h" #include -//#include "RTMath.h" - - #include #include @@ -47,8 +43,6 @@ unsigned long lastRate; int sampleCount; RTQuaternion gravity; -bool reset; // For quaternion calibration - void setup() { int errcode; diff --git a/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.org b/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.org new file mode 100644 index 0000000..3888f19 --- /dev/null +++ b/osc32_9255_rtimulib_espnow/osc32_9255_rtimulib_espnow.org @@ -0,0 +1,260 @@ +#+TITLE: Krmilnik v keglu + +* Vključene knjižnice, definicije +** Nastavljive zadeve +Ker imamo več keglov, najprej povemo, za katerega gre. Za vsak kegel je treba cifro prilagoditi. Mogoče bi nekoč lahko koncipirali boljši sistem dodajanja keglov. + +#+begin_src arduino +#define KEGEL_ID 1 +#+end_src + +Navesti moramo tudi MAC naslov sprejemnika. Mora se skladati s kodo sprejemnika! + +#+begin_src arduino +uint8_t sprejemnikMac[] = {0x08, 0x3A, 0xF2, 0x50, 0xEF, 0x6C }; +#+end_src + +Interval pošiljanja odčitkov senzorjev (v milisekundah). + +#+begin_src arduino +#define DISPLAY_INTERVAL 5 // interval between pose displays +#+end_src + +** i2c +Senzorske vrednosti beremo preko i2c protokola, za kar skrbi knjižnica ~Wire.h~. + +#+begin_src arduino +#include +#+end_src + +** Razbiranje orientacije +Sledeče knjižnice so potrebne za branje senzorja, vključene iz zdaj žal ne več aktivno razvite knjižnice [[https://github.com/RTIMULib/RTIMULib-Arduino][RTIMULib-Arduino]]. Prenesemo zadnjo verzijo in vse direktorije znotraj ~libraries~ skopiramo v ~~/Arduino/libraries~. Nato odkomentiramo primerni senzor v ~~/Arduino/libraries/RTIMULib/RTIMULibDefs.h~, torej ~#define MPU9250_68~. Vsi ostali naj ostanejo odkomentirani! + +#+begin_src arduino +#include "I2Cdev.h" +#include "RTIMUSettings.h" +#include "RTIMU.h" +#include "RTFusionRTQF.h" +#include "CalLib.h" +#+end_src + +** Kalibracijski podatki + +Kegel moramo pred uporabo kalibrirati, s [[file:~/projekti/kegel/ArduinoMagCal/ArduinoMagCal.ino][to skico]]. S tipko ~s~ shranimo parametre kalibracije v ~EEPROM~, od koder ga ta skica kasneje prebere. + +#+begin_src arduino +#include +#+end_src + +** Brezžično povezovanje + +Potrebujemo pa tudi knjižnice za brezžično pošiljanje preko WiFi-ja, z ~ESP-NOW~ komunikacijskim protokolom. + +#+begin_src arduino +#include +#include +#+end_src + +* Podatkovne strukture +** Paket senzorskih podatkov +Vsak brezžični paket pošlje ID kegla, razbran pospešek (z odšteto gravitacijo) po X, Y in Z oseh in pa kvaternion, ki opisuje orientacijo (X Y Z W). + +Rezerviramo eno spremenljivko za odčitek senzorja. + +#+begin_src arduino +typedef struct sensor_msg { + int id; + RTFLOAT aX; + RTFLOAT aY; + RTFLOAT aZ; + RTFLOAT qX; + RTFLOAT qY; + RTFLOAT qZ; + RTFLOAT qW; +} sensor_msg; + +sensor_msg odcitek; +#+end_src + +** Objekti za gibalni senzor + +#+begin_src arduino +RTIMU *imu; // Podatki o senzorju +RTFusionRTQF fusion; // fuzijski objekt +RTIMUSettings settings; // nastavitve senzorja +RTQuaternion gravity; // kvaternion za smer gravitacije +#+end_src + +Števci za ritem pošiljanja paketov. + +#+begin_src arduino +unsigned long lastDisplay; +unsigned long lastRate; +int sampleCount; +#+end_src + +** Podatki o brezžični povezavi + +#+begin_src arduino +esp_now_peer_info_t peerInfo; +#+end_src + +* Vzpostavitev + +Najprej rezerviramo prostor za razbiranje napake in vzpostavimo serijsko povezavo. + +#+begin_src arduino +void setup() { + int errcode; // Prostor za napako + + // Serijski port na navedeni hitrosti + Serial.begin(115200); + // Obvestimo o začenjanju + Serial.println("Starting up..."); +#+end_src + +Vklopimo tudi EEPROM razbiranje ter i2c povezavo s senzorjem. + +#+begin_src arduino + // Init EEPROM based on magnet calibration size requirement + EEPROM.begin(512); + + // I2C init + Wire.begin(); + Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties +#+end_src + +Nato ustvarimo objekt za gibalni senzor in obvestimo o morebitni napaki. + +#+begin_src arduino + // create the imu object + imu = RTIMU::createIMU(&settings); + + Serial.print("ArduinoIMU starting using device "); Serial.println(imu->IMUName()); + if ((errcode = imu->IMUInit()) < 0) { + Serial.print("Failed to init IMU: "); Serial.println(errcode); + } +#+end_src + +Razberemo kalibracijo magnetometra. + +#+begin_src arduino + if (imu->getCalibrationValid()) + Serial.println("Using compass calibration"); + else + Serial.println("No valid compass calibration data"); +#+end_src + +In pa nastavimo izhodiščno (nevtralno) smer gravitacije. + +#+begin_src arduino + gravity.setScalar(0); + gravity.setX(0); + gravity.setY(0); + gravity.setZ(1); +#+end_src + +Števce nastavimo na izhodiščni čas. + +#+begin_src arduino + lastDisplay = lastRate = millis(); + sampleCount = 0; +#+end_src + +WIFI nastavimo na ESP-NOW. + +#+begin_src arduino + WiFi.mode(WIFI_STA); + if (esp_now_init() != ESP_OK) { + Serial.println("Error initializing ESP-NOW"); + return; + } +#+end_src + +Nato nastavimo v začetku definiran MAC naslov sprejemnika, wifi kanal ter nastavimo nekriptiran način delovanja. + +#+begin_src arduino + memcpy(peerInfo.peer_addr, sprejemnikMac, 6); + peerInfo.channel = 0; + peerInfo.encrypt = false; + + if (esp_now_add_peer(&peerInfo) != ESP_OK){ + Serial.println("WIFI registracija ni uspela"); + return; + } +} +#+end_src + +* Zanka delovanja + +TODO opis zanke! + +#+begin_src arduino +void loop() { + unsigned long now = millis(); + unsigned long delta; + RTVector3 realAccel; + RTQuaternion rotatedGravity; + RTQuaternion fusedConjugate; + RTQuaternion qTemp; + int loopCount = 0; + + // get the latest data if ready yet + while (imu->IMURead()) { + // this flushes remaining data in case we are falling behind + if (++loopCount >= 10) + continue; + + fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp()); + + // do gravity rotation and subtraction + + // create the conjugate of the pose + fusedConjugate = fusion.getFusionQPose().conjugate(); + + // now do the rotation - takes two steps with qTemp as the intermediate variable + qTemp = gravity * fusion.getFusionQPose(); + rotatedGravity = fusedConjugate * qTemp; + + // now adjust the measured accel and change the signs to make sense + realAccel.setX(-(imu->getAccel().x() - rotatedGravity.x())); + realAccel.setY(-(imu->getAccel().y() - rotatedGravity.y())); + realAccel.setZ(-(imu->getAccel().z() - rotatedGravity.z())); + + sampleCount++; + if ((delta = now - lastRate) >= 1000) { + + //Serial.print("Sample rate: "); Serial.print(sampleCount); + if (!imu->IMUGyroBiasValid()) { + // Serial.println(", calculating gyro bias"); + } else { + // Serial.println(); + } + + sampleCount = 0; + lastRate = now; + } + + if ((now - lastDisplay) >= DISPLAY_INTERVAL) { + lastDisplay = now; + + odcitek.id = KEGEL_ID; + odcitek.aX = realAccel.x(); + odcitek.aY = realAccel.y(); + odcitek.aZ = realAccel.z(); + odcitek.qX = fusion.getFusionQPose().x(); + odcitek.qY = fusion.getFusionQPose().y(); + odcitek.qZ = fusion.getFusionQPose().z(); + odcitek.qW = fusion.getFusionQPose().scalar(); + + esp_err_t result = esp_now_send(sprejemnikMac, (uint8_t *) &odcitek, sizeof(odcitek)); + + if (result == ESP_OK) { + Serial.println("Uspesno poslano"); + } else { + Serial.println("Napaka pri posiljanju"); + } + } + } +} +#+end_src diff --git a/2022-11-27_kegel.jpg b/slike/2022-11-27_kegel.jpg similarity index 100% rename from 2022-11-27_kegel.jpg rename to slike/2022-11-27_kegel.jpg diff --git a/slike/IMG_20230618_130022.jpg b/slike/IMG_20230618_130022.jpg new file mode 100644 index 0000000..694a74a Binary files /dev/null and b/slike/IMG_20230618_130022.jpg differ diff --git a/slike/IMG_20230618_130038.jpg b/slike/IMG_20230618_130038.jpg new file mode 100644 index 0000000..fbb1ba9 Binary files /dev/null and b/slike/IMG_20230618_130038.jpg differ diff --git a/slike/IMG_20230618_130055.jpg b/slike/IMG_20230618_130055.jpg new file mode 100644 index 0000000..5316900 Binary files /dev/null and b/slike/IMG_20230618_130055.jpg differ diff --git a/slike/IMG_20230618_131305.jpg b/slike/IMG_20230618_131305.jpg new file mode 100644 index 0000000..37f6fd4 Binary files /dev/null and b/slike/IMG_20230618_131305.jpg differ diff --git a/slike/IMG_20230618_131528.jpg b/slike/IMG_20230618_131528.jpg new file mode 100644 index 0000000..f94b9cf Binary files /dev/null and b/slike/IMG_20230618_131528.jpg differ diff --git a/slike/IMG_20230618_131926.jpg b/slike/IMG_20230618_131926.jpg new file mode 100644 index 0000000..c66d9e3 Binary files /dev/null and b/slike/IMG_20230618_131926.jpg differ diff --git a/slike/IMG_20230618_131933.jpg b/slike/IMG_20230618_131933.jpg new file mode 100644 index 0000000..93becbc Binary files /dev/null and b/slike/IMG_20230618_131933.jpg differ