Urejanje dokumentacij, literate programming WIP koda za krmilnik

main
Jurij Podgoršek 2024-02-01 00:57:24 +01:00
parent 1f5d10d038
commit b16db03288
13 changed files with 383 additions and 61 deletions

View File

@ -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

View File

@ -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".

122
README.org 100644
View File

@ -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~.

View File

@ -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;

View File

@ -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

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 KiB