Urejanje dokumentacij, literate programming WIP koda za krmilnik
|
@ -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
|
26
README.md
|
@ -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".
|
|
@ -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~.
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// ESP32 Dev Module
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
// ID kegla mora bit unikaten za vsakega! (se poslje poleg parametrov)
|
||||
#define KEGEL_ID 1
|
||||
|
||||
#include <Wire.h>
|
||||
// IMU libraries
|
||||
#include "I2Cdev.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
@ -13,9 +12,6 @@
|
|||
#include "CalLib.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
//#include "RTMath.h"
|
||||
|
||||
|
||||
#include <esp_now.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
|
@ -47,8 +43,6 @@ unsigned long lastRate;
|
|||
int sampleCount;
|
||||
RTQuaternion gravity;
|
||||
|
||||
bool reset; // For quaternion calibration
|
||||
|
||||
void setup() {
|
||||
int errcode;
|
||||
|
||||
|
|
|
@ -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 <Wire.h>
|
||||
#+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 <EEPROM.h>
|
||||
#+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 <esp_now.h>
|
||||
#include <WiFi.h>
|
||||
#+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
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 355 KiB |
After Width: | Height: | Size: 401 KiB |
After Width: | Height: | Size: 372 KiB |
After Width: | Height: | Size: 379 KiB |
After Width: | Height: | Size: 664 KiB |
After Width: | Height: | Size: 657 KiB |