Realizácia projektu detekcie pohybu
1. | Opis použitých technológií |
2. | Analýza požiadaviek pre detekciu pohybu |
3. | Realizácia projektu detekcie pohybu |
4. | Zhodnotenie výsledkov projektu detekcia pohybu
|
Obsah
Obsahom tejto kapitoly je opis postupu pri tvorbe jednotlivých častí bakalárskej práce. Úvod je zameraný na opis prototypu komunikačného protokolu vytvoreného pre potreby komunikácie cez sériový port. Ďalej sa venujeme tvorbe firmvéru, pomocou ktorého bude mikrokontrolér komunikovať so senzormi a počítačom a prijímať a odosielať namerané údaje. Na realizáciu budú použité dve aplikácie a to STM32 CubeMX a SW4STM32. Na záver sa budeme venovať popisu návrhu používateľského rozhrania desktopovej aplikácie, ktorá bude spracovávať hodnoty prijaté z mikrokontroléra a výsledky bude vizualizovať v trojrozmernom priestore. Pri tvorbe aplikácie použijeme Visual Studio 2017.
Pri pôvodnom návrhu sme uvažovali, že mikrokontrolér bude zabezpečovať ako nastavenie, tak aj komunikáciu so senzormi. Prijaté údaje by následne spracoval a výsledky odoslal do počítača. Neskôr sme sa však rozhodli pre jednoduchšie riešenie z hľadiska činností, ktoré bude mikrokontrolér vykonávať. Jeho úlohou je prijímať príkazy z počítača cez sériový port. Po spracovaní príkazu, rozhodne, či ide o príkaz pre nastavenie senzorov, alebo o žiadosť pre odoslanie nameraných hodnôt. V prípade, že ide o príkaz, nastaví požadované parametre senzorov. Ak naopak ide o žiadosť, načíta dáta zo senzorov do buffra a ten spätne odošle cez sériový port na spracovanie do počítača. Pre toto riešenie sme sa rozhodli z dôvodu, že počítač disponuje výrazne vyšším výpočtovým výkonom a spracovanie údajov tak beh aplikácie nespomalí. Vďaka tomu môžeme všetok výkon, ktorým mikrokontrolér disponuje, použiť na spracovanie príkazov/žiadostí a následnú reakciu. Počítač zároveň riadi tok dát, nakoľko vydáva žiadosti o odoslanie dát až potom, čo predchádzajúce údaje spracuje. Toto riešenie nám takisto umožnilo pridať možnosť nastavenia citlivosti a frekvencie senzorov do aplikácie a odstránilo nutnosť meniť tieto hodnoty v kóde firmvéru. Pre potreby komunikácie cez sériový port sme navrhli prototyp jednoduchého komunikačného protokolu, vďaka ktorému vieme odosielať príkazy o veľkosti dvoch bajtov.
Návrh komunikačného protokolu
Táto podkapitola obsahuje opis štruktúry a fungovania prototypu komunikačného protokolu, ktorý bol navrhnutý za účelom komunikácie počítača s mikrokontrolérom cez sériový port. Cieľom tohto protokolu je zjednodušiť komunikáciu a umožniť odosielanie žiadostí pre zápis a čítanie hodnôt medzi počítačom a mikrokontrolérom. V závere podkapitoly sa nachádza vzorový príklad použitia tohto komunikačného protokolu.
Základným funkčným prvkom tohto protokolu je bajt. Kompletná správa, ktorú odosiela počítač sa skladá z dvoch bajtov. Prvý bajt obsahuje informácie o tom, či ide o zápis, alebo čítanie a či ide o žiadosť určenú pre akcelerometer alebo gyroskop. Protokol nám umožňuje odosielať konfiguráciu citlivosti a frekvencie merania samostatne. V našom riešení však využívame možnosť nastaviť obe hodnoty v jednej správe. Štruktúra druhého bajtu závisí od typu žiadosti. V prípade, že ide o žiadosť pre nastavenie senzorov, nachádzajú sa v ňom hodnoty s nastavením, naopak v prípade, že ide o žiadosť pre čítanie nameraných údajov, obsahuje počet požadovaných meraní. Hodnoty citlivosti a frekvencie merania sú načítané z okna pre nastavenie a sú upravené do formátu, ktorý je uvedený v technickej dokumentácii výrobcu senzorovej dosky. Bližší opis okna a možnosti nastavenia senzorov sa nachádzajú v časti 1.3.1.2 a v tabuľkách [AccScale] a [GyroScale]. Hoci posledné tri bity z tohto bajtu umožňujú nastavenie priepustnosti senzorov, rozhodli sme sa ich nevyužiť a priepustnosť tak zodpovedá zvolenej frekvencii. Po upravení sú dáta uložené do druhého bajtu správy a odoslané stlačením tlačidla pre spustenie komunikácie spoločne s prvým informačným bajtom. Ak však ide o žiadosť pre čítanie nameraných údajov, načíta sa z okna hodnota počtu požadovaných meraní, ktorá je uložená do druhého bajtu a odošle sa spolu s prvým bajtom.
Veľkosť odpovede z mikrokontroléra môže byť rôzna a závisí od typu žiadosti a počtu vyžiadaných meraní. V prípade, že sa jedná žiadosť pre nastavenie senzorov, mikrokontrolér neodošle žiadnu odpoveď. Ak ide o žiadosť pre čítanie údajov, odošle do počítača požadovaný počet meraní uložených v poli a zoradených za sebou bez akejkoľvek identifikačnej hlavičky.
Packet | ||||||||||||||||
Byte | Byte 0 | Byte 1 | ||||||||||||||
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Prvý bajt- Byte 0 | ||||||||
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
dir | dest | cd | setting |
dir | 01 = set | Rozhoduje o tom, či sa jedná o zápis |
10 = get | alebo čítanie z registrov | |
dest | 01 = acc | Rozhoduje o tom, či je adresátom |
10 = gyro | žiadosti akcelerometer alebo gyroskop | |
cd | 0 = command | Rozhoduje o tom, či sa budú čítať |
1 = data | namerané dáta alebo nastavenia |
setting | Funkcia | ||
0 | 0 | 1 | Nastavenie citlivosti |
0 | 1 | 0 | Nastavenie frekvencie |
0 | 1 | 1 | Nastavenie citrlivosti a frekvencie |
Druhý bajt- Byte 1 - žiadosť o nastavenie | ||||||||
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | frekvencia | citlivosť | priepustnosť |
Druhý bajt- Byte 1 - žiadosť o čítanie | ||||||||
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | počet meraní |
Citlivosť akcelerometra
- 00: [math]\pm[/math]2 g
- 01: [math]\pm[/math]16 g
- 10: [math]\pm[/math]4 g
- 11: [math]\pm[/math]8 g
Frekvencia snímania akcelerometra
- 001: 10 Hz
- 010: 50 Hz
- 011: 119 Hz
- 100: 238 Hz
- 101: 476 Hz
- 110: 952 Hz
Tabuľka 3.7: Možnosti konfigurácie akcelerometra
Citlivosť gyroskopu
- 00: [math]\pm[/math]245 dps
- 01: [math]\pm[/math]500 dps
- 10: [math]\pm[/math]2000 dps
Frekvencia snímania gyroskopu
- 001: 14.9 Hz
- 010: 59.5 Hz
- 011: 119 Hz
- 100: 238 Hz
- 101: 476 Hz
- 110: 952 Hz
Tabuľka 3.7: Možnosti konfigurácie gyroskopu
Príklad správ odoslaných prostredníctvom sériového portu:
- 01010110|11000000 - odoslanie žiadosti pre nastavenie citlivosti [math]\pm[/math]2g a frekvencie merania 952Hz pre akcelerometer
- 01100110|10101000 - odoslanie žiadosti pre nastavenie citlivosti [math]\pm[/math]245dps a frekvencie merania 476Hz pre gyroskop
- 10011000|00010000 - odoslanie žiadosti pre čítanie 16 meraní z akcelerometra
- 10101000|00001000 - odoslanie žiadosti pre čítanie 8 meraní z gyroskopu
Tvorba firmvéru pre mikrokontrolér
Jedným z hlavných cieľov práce je navrhnúť a implementovať firmvér pre mikrokontrolér, ktorý bude komunikovať so senzorovou doskou. V tejto podkapitole sa zameriame na návrh a postup tvorby tohto firmvéru. Komunikácia medzi zariadeniami bude prebiehať cez komunikačné rozhranie SPI. Úlohou mikrokontroléru bude spracovať správy z počítača a na ich základe zapísať nastavenia senzorov do registrov alebo prečítať namerané hodnoty uložené v registroch. V prípade čítania hodnôt z registra, uloží získané hodnoty do buffra a ten odošle späť do počítača cez sériový port.
Počiatočná konfigurácia mikrokontroléra
Pri tvorbe firmvéru bolo nutné vykonať počiatočnú konfiguráciu mikrokontroléra. Konfigurácia prebehla v aplikácii STM32 CubeMX, v ktorej bola nastavená funkčnosť použitých pinov pri riešení tohto projektu. Vzhľadom na požiadavky tohto zadania boli vyhradené piny pre komunikáciu cez SPI rozhranie a sériový port, ako aj piny pre určenie taktu procesora a signalizačnú LED diódu.
Opis použitých pinov
Táto časť obsahuje krátky opis pinov použitých pri riešení zadania bakalárskej práce. Pre umožnenie komunikácie medzi mikrokontrolérom, počítačom a senzromi boli vyhradené piny vyznačené zelenou farbou na obrázku 1.1.
- GPIO - piny bez špecifickej funkcie. Môžu slúžiť ako vstupné aj výstupné piny a ich funkcia sa dá nastaviť softvérovo [3]. V našom riešení sme sa rozhodli využiť jeden z týchto pinov ako výstupný a jeho úlohou je svetelná signalizácia spracovania príkazov pomocou LED diódy.
- LD3 [Green] - ovládanie signalizačnej LED diódy
- SPI1 - piny vyhradené pre SPI rozhranie. Pre umožnenie plne duplexnej komunikácie boli vyhradené štyri komunikačné linky, ktoré sú prepojené so senzorovou doskou.
- SPI1_CS - voľba slave zariadenia
- SPI1_MISO - odosielanie dát z master do slave zariadenia
- SPI1_MOSI - prijímanie dát zo slave do master zariadenia
- SPI1_SCK - generovanie SPI taktu
- SWD - umožňujú ladenie cez rozhranie sériového portu.
- SWCLK - obojsmerná dátová linka
- SWDIO - takt riadený hostom
- VCP - komunikačné linky vyhradené pre komunikáciu cez rozhranie sériového portu. Pri našom riešení ich využívame pre komunikáciu medzi počítačovou aplikáciou a mikrokontrolérom.
- VCP_TX - odosielanie dát do počítača
- VCP_RX - prijímanie dát z počítača
Firmvér pre mikrokontrolér
Obsahom tejto časti je postup programovania firmvéru, ktorý bude riadiť mikrokontrolér. Úvod je venovaný spracovaniu žiadosti z počítača a opisu dátových štruktúr použitých pri riadení komunikácie cez SPI rozhranie. Ďalej sa tu nachádza opis funkcií, ktoré boli vytvorené za účelom zápisu a čítania údajov určených pre prácu s registrami senzorov. Pri písaní kódu používame voľne dostupnú knižnicu HAL, ktorá je funkčne orientovaná a umožňuje tak jednoduchý prístup k funkciám mikrokontroléra.
Spracovanie žiadosti
Jednou zo základných funkcií mikrokontroléra je spracovanie žiadosti z počítača. Počítač odosiela žiadosti vo forme dát uložených v dvoch bajtoch. Ide teda o jednoduchý prototyp komunikačného protokolu, ktorý využívame pre komunikáciu cez rozhranie sériového portu. Opis samotného protokolu sa nachádza v podkapitole 1.1. Pre príjem dát z nadradeného počítača je použité rozhranie UART v režime prerušenia, čo znamená, že po prijatí definovaného počtu bajtov sa samočinne spustí rutina obsluhy prerušenia, kde sa prijaté údaje môžu spracovať. V našej implementácii sa v obsluhe prerušenia pre rozhranie UART nastaví príznak interrupt_flag, ktorý spustí spracovanie požiadavky.
Na základe prvého bajtu rozhodne mikrokontrolér či ide o žiadosť pre zápis alebo čítanie údajov. Následne zistí, ktorému zariadeniu z dvojice akcelerometer-gyroskop žiadosť patrí. V prípade, že ide o zápis dát, odošle hodnotu z druhého prijatého bajtu funkcii zodpovednej za konfiguráciu senzorov. Ak je naopak obsahom žiadosti príkaz na čítanie dát, odošle hodnotu z druhého prijatého bajtu funkcii zodpovednej za čítanie dát z registrov a vykoná počet požadovaných meraní. Hodnoty z merania sa uložia do buffra a ten je odoslaný späť do počítača.
while (1){
if(uart_dataReady_flag == 1){
uart_dataReady_flag = 0;
com_info = uart_buffer[0]; com_data = uart_buffer[1];
com_getset = com_info & 0xC0; com_device = com_info & 0x30;
HAL_UART_Receive_IT(&huart2, uart_buffer, 2);
switch (com_getset){
case DEVICE_CONFIG:
switch (com_device){
case DEVICE_ACC:
lsm9ds1_device_set(CTRL_REG6_XL, com_data);
break;
case DEVICE_GYRO:
lsm9ds1_device_set(CTRL_REG1_G, com_data);
break;
default: break;
}
lsm9ds1_mode_set(FIFO_CTRL);
break;
case DEVICE_DATA:
switch (com_device){
case DEVICE_ACC:
lsm9ds1_device_read(LSM9DS1_OUT_XL, com_data);
break;
case DEVICE_GYRO:
lsm9ds1_device_read(LSM9DS1_OUT_G, com_data);
break;
}
HAL_UART_Transmit(&huart2, driver.data_out,
sizeof(driver.data_out), 50);
break;
}
}
}
Komunikačný driver
Pre realizáciu komunikácie medzi mikrokontrolérom a senzormi bolo použité rozhranie SPI. V nasledujúcom zdrojovom kóde je vytvorená dátová štruktúra, ktorá reprezentuje toto rozhranie. Obsahuje premennú address pre uloženie adresy registra senzora, z/do ktorého sa budú dáta čítať/zapisovať, buffer pre ukladanie dát používaných pri komunikácii data a buffer pre uloženie prečítaných nameraných hodnôt data_out. Driver sa využíva pri zápise a čítaní údajov cez SPI rozhranie medzi mikrokontrolérom a senzormi.
typedef struct{
SPI_HandleTypeDef *hspi;
uint8_t address;
uint8_t data[12];
uint8_t data_out[7*16];
GPIO_TypeDef* port;
uint32_t pin_cs;
}Lsm9ds1_Driver;
/** Slúži na prístup k rozhraniu SPI na nízkej úrovni. */
Lsm9ds1_Driver driver;
void lsm9ds1_init(SPI_HandleTypeDef *hspi,
GPIO_TypeDef* port, uint32_t cs){
driver.hspi = hspi;
driver.port = port;
driver.pin_cs = cs;
}
Konfigurácia senzorov
Ďalej bola vytvorená funkcia, ktorá slúži na zápis požadovaného nastavenia do zvoleného registra. Jej úlohou je nastavenie citlivosti a frekvencie merania dát. V prípade zavolania funkcie sa do komunikačného drivera uloží adresa registra, ktorý má byť nastavený. Funkcia následne odošle hodnoty nastavenia do externej funkcie set_data
, ktorá uloží nastavenie na druhú pozíciu v buffri a na záver zavolá funkciu spi_write
, ktorá vykoná zápis nastavení cez SPI rozhranie.
void lsm9ds1_device_set(uint8_t address, uint8_t com_data){
driver.address = address;
set_data(0, com_data);
spi_write(1);
}
Nastavenie operačného režimu
Z dôvodu urýchlenia komunikácie medzi počítačom a mikrokontrolérom sme sa rozhodli nastaviť operačný režim senzorov na režim nepretržitého získavania dát. Toto nastavenie je dosiahnuté pomocou funkcie lsm9ds1_mode_set
, ktorá sa vykoná po konfigurácii senzorov opísanej vyššie. Po nastavení nepretržitého režimu sú v registroch akcelerometra a gyroskopu neustále ukladané nové hodnoty merania, ktoré sa odosielajú až po prijatí žiadosti z počítača. Registre disponujú buffrom o veľkosti 32 nameraných hodnôt, pričom jedna hodnota zodpovedá jednému bajtu. Po zaplnení buffra neprečítanými hodnotami, začne zariadenie automaticky prepisovať staré hodnoty a nahrádza ich novými. Z tohto dôvodu sú k dispozícii dáta kedykoľvek a komunikácia nie je brzdená meraním.
void lsm9ds1_mode_set(uint8_t address){
driver.address = address;
uint8_t data = 0xDF;
set_data(0, data);
spi_write(1);
}
Čítanie nameraných hodnôt
Po úspešnom nastavení senzorov je zariadenie pripravené na čítanie nameraných údajov z registrov akcelerometra a gyroskopu. Ak mikrokontrolér príjme žiadosť o odoslanie nameraných hodnôt, zavolá funkciu lsm9ds1_device_read
. Funkcia uloží adresu registra, z ktorého budú čítané hodnoty, do komunikačného drivera a následne vykoná počet požadovaných meraní zavolaním funkcie spi_read
.
void lsm9ds1_device_read(uint8_t address, uint8_t com_data){
driver.address = address;
int i, j;
for(i = com_data - 1; i >= 0; i--) {
spi_read(6);
for(j = 0; j < 7; j++) {
driver.data_out[j + (i * 7)] = driver.data_out[j];
}
}
}
Uloženie údajov do buffra
Táto funkcia slúži na uloženie nastavení senzorov na požadovanú pozíciu pozíciu v buffri. Po zavolaní príjme hodnotu indexu a premennú obsahujúcu nastavenie pre senzor a uloží ho o jednu pozíciu ďalej, než je hodnota indexu.
void set_data(uint8_t index, uint8_t data_x){
driver.data[index + 1] = data_x;
}
Zápis dát do registra
Funkcia príjme počet bajtov, ktoré budú použité pri komunikácii cez SPI rozhranie. Následne uloží na nultú pozíciu buffra adresu registra, ku ktorej je pripočítaná hodnota 0x00 indikujúca zápis dát. Po uložení je aktivované SPI rozhranie a odošle sa nastavenie. Akonáhle sa prenos dát skončí, SPI rozhranie je deaktivované.
void spi_write(uint8_t n){
driver.data[0] = DIRECTION_WRITE | (driver.address & DIRECTION_MULTIPLIER);
CS_Activate();
HAL_SPI_Transmit(driver.hspi, driver.data, n + 1, 50);
CS_Deactivate();
}
Na grafe 1.3 možno vidieť priebeh komunikácie cez SPI rozhranie zobrazený na logickom analyzátore. V tomto prípade sa jedná o dvojnásobný zápis nastavenia do registrov senzora. Pre začatie komunikácie zmení master úroveň SS pinu z logickej 1 na úroveň logickej 0, čím aktivuje zariadenie slave. Na grafe z analyzátora sa táto činnosť zobrazí na kanáli 6, kde možno vidieť aktiváciu a deaktiváciu SPI rozhrania po vykonaní zápisu. Po aktivácii komunikačného rozhrania, odošle master dva bajty do zariadenia slave cez komunikačnú linku MOSI. Prvý bajt obsahuje adresu registra 0x20, do ktorého sa bude zapisovať a v druhom bajte sa nachádza hodnota 0xC0, ktorá slúži na nastavenie frekvencie snímania a citlivosti akcelerometra. Po vykonaní zápisu zmení master úroveň SS pinu z logickej 0 na úroveň logickej 1 a komunikáciu ukončí. Priebeh druhého zápisu je rovnaký, no v tomto prípade odosiela master hodnotu 0xDF na adresu 0x2E, čím nastaví nepretržitý režim snímania dát. Komunikácia prebieha len na linke MOSI, pretože dáta sú odosielané len zo zariadenia master a nie je potrebná odpoveď od zariadenia slave.
inline void CS_Activate(void){
driver.port->BRR=driver.pin_cs;
}
inline void CS_Deactivate(void){
driver.port->BSRR=driver.pin_cs;
}
Čítanie dát z registra
Funkcia príjme počet bajtov, ktoré budú použité pri komunikácii cez SPI rozhranie. Následne uloží na nultú pozíciu buffra adresu registra, ku ktorej je pripočítaná hodnota 0x80 indikujúca čítanie dát a zmaže dáta uložené na druhej pozícii v buffri. Po vykonaní prvých dvoch príkazov je aktivované SPI rozhranie a dáta uložené v registroch akcelerometra alebo gyroskopu sú uložené do buffra driver.data_out
. Akonáhle sa prenos dát skončí, SPI rozhranie je deaktivované.
void spi_read(uint8_t n){
driver.data[0] = DIRECTION_READ | (driver.address & DIRECTION_MULTIPLIER);
driver.data[1] = 0;
CS_Activate();
HAL_SPI_TransmitReceive(driver.hspi, driver.data,
driver.data_out, n + 1, 50);
CS_Deactivate();
}
Graf 1.4 znázorňuje priebeh čítania nameraných hodnôt z registra akcelerometra, zobrazený na logickom analyzátore. Rovnako ako v prípade zápisu dát, začne master komunikáciu zmenou úrovne SS pinu z logickej 1 na úroveň logickej 0. Cez linku MOSI sa odošle bajt s adresou registra akcelerometra, z ktorého sú čítané dáta. Odpoveď zariadenia slave pozostáva zo šiestich za sebou idúcich bajtov, ktoré obsahujú tri dvojice hodnôt nameraných akcelerometrom a je odoslaná cez komunikačnú linku MISO. Po odoslaní dát je komunikácia ukončená zariadením master zmenou úrovne SS pinu z logickej 0 na úroveň logickej 1. Keďže hodnoty merania sú reprezentované 16-bitovým číslom, ale veľkosť registrov je len 8 bitov, sú tieto hodnoty rozdelené do dvoch za sebou prichádzajúcich 8-bitových čísiel [19]. Prvé číslo zodpovedá dolnému bajtu nameranej hodnoty a druhé číslo hornému bajtu. Tieto bajty sú neskôr spojené pri spracovaní nameraných hodnôt v desktopovej aplikácii.
Motion 3D aplikácia
Hlavným cieľom tejto práce bolo vytvoriť aplikáciu, ktorá bude použitá pri spracovaní a vizualizácii údajov získaných zo senzorov. Táto podkapitola je venovaná opisu používateľského rozhrania aplikácie a tvorbe zdrojového kódu zodpovedného za beh aplikácie, riadenie komunikácie a spracovanie údajov. Aplikácia bola vytvorená vo vývojom prostredí Visual Studio 2017 za použitia WPF. Dizajn aplikácie bol realizovaný v značkovacom jazyku XAML a zdrojový kód bol napísaný v objektovo-orientovanom programovacom jazyku C#.
Návrh používateľského rozhrania aplikácie
Táto čast sa zaoberá návrhom a vytvorením používateľského rozhrania desktopovej aplikácie. Aplikácia musí obsahovať možnosť nastavenia sériového portu, konfigurácie senzorov a okno pre zobrazenie 3D modelu, ktorý bude slúžiť na vizualizáciu dát. Dizajn rozhrania bol vytvorený vo WPF API pomocou značkovacieho jazyka XAML. Jednou z hlavných výhod WPF je tvorba vizuálnych prvkov za použitia vektorovej grafiky [8]. Vytvorené prvky tak budú vždy ostré aj pri niekoľkonásobnom zväčšení.
Hlavné okno
Prvým krokom pri tvorbe dizajnu aplikácie bolo vytvorenie hlavného okna. To obsahuje tlačidlo pre zatvorenie aplikácie, tlačidlá pre nastavenie senzorov a sériového portu, tlačidlá pre spustenie komunikácie a čítania dát a 3D priestor s 3D modelom pre vizualizovanie dát. Zároveň obsahuje dva kontrolné prvky, ktoré indikujú, či boli vykonané všetky potrebné nastavenia a indikátory veľkosti zrýchlenia a uhlu natočenia. V prípade, že používateľ nevykonal úplné nastavenie senzorov alebo portu, nebude mu povolené začať komunikáciu s mikrokontrolérom. Akonáhle však nastavenie dokončí, aplikáciu mu povolí prístup k nadviazaniu spojenia cez sériový port. Po úspešnom pripojení aplikácie ku mikrokontroléru sa odomkne tlačidlo na spustenie čítania dát. Ak sú zariadenia pripojené, nie je možné meniť žiadne z nastavení, až pokým komunikácia nebude ukončená stlačením tlačidla. Všetky tlačidlá a indikátory, vrátane ich vzhľadu a logiky, použité pri tvorbe hlavného okna boli vytvorené pre účely použitia tejto aplikácie.
Okná s nastavením
Nakoľko jednou z požiadaviek bolo pridať možnosť nastavenia sériového portu a konfigurácie senzorov, vytvorili sme pre tento účel samostatné okná.
Prvým oknom je okno s nastavením sériového portu. Okno obsahuje prepínače, ktoré umožňujú výber medzi odporúčanými a vlastnými nastaveniami. Ďalej obsahuje polia, v ktorých sa nachádzajú zoznamy s možnosťou voľby parametrov, ako napríklad prenosová rýchlosť alebo parita, ktoré sa sprístupnia po zvolení možnosti vlastných nastavení. Zoznam s názvami dostupných portov je prístupný aj v prípade voľby odporúčaných nastavení. V prípade zmeny ktoréhokoľvek z odporúčaných nastavení je aktuálne nutné zmeniť toto nastavenie manuálne aj v zdrojovom kóde firmvéru a v aplikácii STM32 CubeMX, ktorá generuje inicializačný kód vrátane týchto nastavení.
V druhom okne sa rovnako nachádzajú prepínače, ktorými možno prepínať medzi odporúčanými a vlastnými nastaveniami. Okno poskytuje možnosť výberu zariadenia, ktoré bude použité pri detekcii pohybu. Na výber je akcelerometer, gyroskop a kombinácia oboch zariadení. Po zvolení zariadenia sa používateľovi sprístupnia zoznamy s možnosťou nastavenia citlivosti a frekvencie merania pre dané zariadenie. Na záver je možné nastaviť počet meraní, ktoré bude mikrokontrolér odosielať v jednotlivých správach, pričom hodnota sa môže pohybovať v rozsahu 1-16.
Citlivosť | Frekvencia | Citlivosť | Frekvencia |
[math]\pm[/math]2g | 10Hz | [math]\pm[/math]245dps | 14,9Hz |
[math]\pm[/math]4g | 50Hz | [math]\pm[/math]500dps | 59,5Hz |
[math]\pm[/math]8g | 119Hz | [math]\pm[/math]2000dps | 119Hz |
[math]\pm[/math]16g | 238Hz | - | 238Hz |
- | 476Hz | - | 476Hz |
- | 952Hz | - | 952Hz |
[Settings_table]
3D priestor
Posledným krokom pri tvorbe dizajnu aplikácie bolo pridanie trojrozmerného priestoru vrátane objektu, ktorý bude reprezentovať výsledné hodnoty získané z merania. Keďže sme sa rozhodli pre použitie komplexnejšieho modelu, museli sme do našej aplikácie nainštalovať plugin pre zobrazenie tohto modelu. Rozhodli sme sa pre rozšírenie Helix Toolkit, ktoré obsahuje všetky nástroje potrebné pre zobrazenie nášho objektu. Je to open source knižnica založená na platforme .NET [5]. Bola vytvorená s cieľom zjednodušenia práce s 3D obsahom vo WPF a zároveň pridáva niekoľko užitočných funkcií, ktoré WPF štandardne neponúka.
Pre implementáciu Helix funkcií bolo nutné nainštalovať plugin prostredníctvom správcu balíkov Visual Studia a následne zahrnúť zobrazenie do XAML kódu hlavného okna a rovnako aj zdrojového kódu v C#.
ModelVisual3D device3D = new ModelVisual3D();
device3D.Content = DisplayObject(MODEL_PATH);
Visualisation3D.Children.Add(device3D);
//...
private Model3D DisplayObject(string model){
Model3D Device = null;
try {
ModelImporter import = new ModelImporter();
Device = import.Load(model);
}catch (Exception e)
{ MessageBox.Show("Chýbajúci model: " + e.StackTrace); }
return Device;
}
Spracovanie údajov v aplikácii
V tejto časti sa nachádza postup vytvorenia dôležitých funkcií zdrojového kódu desktopovej aplikácie. Úvod obsahuje funkcie potrebné pre vykonanie konfigurácie sériového portu a senzorov a nadviazanie komunikácie s mikrokontrolérom. Ďalej sa pozrieme na funkcie určené na spracovanie údajov nameraných pohybovými senzormi a ich prepočet na hodnoty použiteľné pri vizualizácii a na záver si priblížime ako funguje samotná vizualizácia objektu v trojrozmernom priestore.
Nastavenie sériového portu
Prvým krokom pri pokuse o nadviazanie komunikácie medzi mikrokontrolérom a počítačom bolo nastavenie správnych parametrov sériového portu. To je vykonané pomocou funkcie Serial_Port_Set
, ktorá načíta potrebné parametre z okna dedikovaného pre jeho nastavenie. Aby spojenie medzi zariadeniami fungovalo, je nutné nastaviť správnu prenosovú rýchlosť. Nastavenie sa vykoná po stlačení tlačidla pre spustenie komunikácie medzi aplikáciou a mikrokontrolérom.
Konfigurácia senzorov
Ďalším krokom bola konfigurácia senzorov akcelerometra a gyroskopu, ktorá sa rovnako ako nastavenie sériového portu vykoná po stlačení tlačidla pre spustenie komunikácie medzi počítačom a mikrokontrolérom. Funkcia Sensor_Devices_Set
najskôr nastaví prvý bajt správy do formátu určeného pre zápis dát, vytvoreného podľa komunikačného protokolu opísaného v podkapitole 1.1. Následne načíta používateľom zvolené hodnoty citlivosti a frekvencie snímania zo zoznamov uložených v okne pre nastavenie senzorov a upraví ich podľa technickej dokumentácie výrobcu do formátu použiteľného pre konfiguráciu senzorov. Výslednú hodnotu konfigurácie uloží do druhého bajtu a spojí ho s prvým informačným bajtom do jednej spoločnej správy. Hodnoty oboch bajtov sú po spojení prevedené do hexadecimálnej sústavy. Na záver funkcia odošle správu príkazom port.Write do mikrokontroléra, kde sa spracuje a vykoná sa konfigurácia senzorov.
Čítanie nameraných hodnôt
Po úspešnom odoslaní a nastavení senzorov je zariadenie pripravené na meranie a odosielanie nameraných hodnôt do počítača. Prenos údajov je inicializovaný žiadosťou, ktorú pošle počítač vo forme správy cez sériový port. Mikrokontrolér správu príjme, spracuje a prečíta požadovaný počet hodnôt z registrov senzorov. Prečítané hodnoty uloží do buffra a ten odošle spätne do aplikácie. Odchytávanie prichádzajúcich dát má na starosti event, ktorý sa spustí hneď ako zaznamená, že cez sériový port prišli dáta. Prijaté dáta uloží do buffra a odošle ich na spracovanie do dedikovanej funkcie.
private void Receive(object sender, SerialDataReceivedEventArgs e){
int bytes = port.BytesToRead;
byte[] Data_Buffer = new byte[bytes];
port.Read(Data_Buffer, 0, bytes);
Collect_Raw_Data(Protocol_Unit_Acc, Data_Buffer);
if ((DataProcessed == true)
&& (Switch_Button_Read.Switch_State1 == true)) {
Thread.Sleep(10);
if (port.IsOpen){
port.Write(Merged_Bytes, 0, 2);
DataProcessed = false;
}
}
}
Spracovanie nameraných hodnôt
Funkcia Collect_Raw_Data
príjme buffer s nameranými hodnotami a spracuje ich do podoby použiteľnej pri výpočte zrýchlenia. Nakoľko sú dáta z akcelerometra a gyroskopu vo veľkosti 16 bitov a registre, v ktorých sú uložené, sú len 8-bitové, je nutné dáta najskôr spojiť do jednej 16-bitovej hodnoty. To dosiahneme implementovaním vzorca [Spojenie] do zdrojového kódu aplikácie. Keďže žiadosť pre čítanie údajov môže obsahovať požiadavku pre odoslanie 1-16 meraní, sú dáta pre jednotlivé osi (X, Y, Z) ukladané v 16-bitovom formáte do patričnej premennej, z ktorej je následne vypočítaná priemerná hodnota. [math]\label{Spojenie}
X_{i}\; =\; X_{Hi}\; *\; 256\; +\; X_{Li}[/math] kde:
- [math]X_{i}[/math] - je súčet hornej a dolnej nameranej hodnoty z akcelerometra,
- [math]X_{Hi}[/math] - je horný bajt nameranej hodnoty z akcelerometra,
- [math]X_{Li}[/math] - je dolný bajt nameranej hodnoty z akcelerometra.
Výsledná hodnota je číslo v rozsahu -32768..32767 a je uložená v doplnkovom kóde. Preto je potrebné previesť ju na znamienkovú hodnotu. Získané dáta sú následne spriemerované, čím sa dosiahne väčšia presnosť merania. Po vypočítaní priemerných hodnôt sú dáta odoslané do funkcie na prepočet z nameraných hodnôt na zrýchlenie v mG.
[math]X\; =\; \frac{\sum\limits_{i=0}^{n}\; {X}_{i} }{n}[/math] kde:
- [math]X[/math] - je priemerná hodnota z počtu požadovaných meraní.
- [math]\sum X_i[/math] - je súčet hôdnot získaných z akcelerometra,
- [math]n[/math] - je počet požadovaných meraní.
for (int i = 0; i < Count; i++){
Sample_X = (SerialData[2 + i * 7] * 256) + SerialData[1 + i * 7];
if (Sample_X >= 32768)
Sample_X -= 65536;
Sum_X += Sample_X;
}
Raw_DataX = Sum_X / Count;
Výpočet zrýchlenia z nameraných hodnôt
Dáta sú vo funkcii Convert_Raw_Data
vynásobené konštantou v závislosti od zvolenej citlivosti pohybového senzora. Výsledkom tohto násobenia je zrýchlenie, ktoré môžme použiť pri výpočte uhlu natočenia v trojrozmernom priestore. Ak je nastavená citlivosť akcelerometra [math]\pm[/math]2g, získame rozsah hodnôt -2 až +2, čo je celkovo 4g. Keďže sú výstupné hodnoty akcelerometra udávané v pomere mg/LSB [19], vykonáme prevod a získame hodnotu 4000mG. Nakoľko sú hodnoty z akcelerometra v 16-bitovom formáte, je možné získať 65 535 rôznych meraní v rozsahu -2g a +2g. Po vydelení rozsahu možným počtom rôznych získaných hodnôt získavame konštantu, ktorú použijeme pri prevode surových dát na zrýchlenie. Hodnoty konštánt pre jednotlivé nastavenia citlivosti sú dostupné aj v technickej dokumentácii výrobcu senzora. [math]4000mg / 65 535\; =\; 0,061[/math] Táto konštanta je následne uložená v premennej zdrojového kódu aplikácie Acc_Scale_2g a použitá pri výpočte pre zvolenú citlivosť. [math]A_X = 16951 * 0,061 = 1906,37mG[/math]
Citlivosť | Konštanta | Citlivosť | Konštanta |
[math]\pm[/math]2g | 0,061 | [math]\pm[/math]245dps | 8,75 |
[math]\pm[/math]4g | 0,122 | [math]\pm[/math]500dps | 17,50 |
[math]\pm[/math]8g | 0,244 | [math]\pm[/math]2000dps | 70 |
[math]\pm[/math]16g | 0,732 | - | - |
[Constants_table]
Výpočet uhlov natočenia objektu
Pri výpočte uhlov bola dodatočne použitá knižnica Math, ktorá obsahuje nielen bežné matematické funkcie ale aj goniometrické funkcie [10] potrebné k výpočtu uhlov. Na základe hodnôt z akcelerometra sme schopní určiť orientáciu objektu v dvoch osiach a vypočítať tak uhol sklonu (naklonenie okolo osi Y) a natočenia (natočenie okolo osi X). Ak by sme chceli vypočítať orientáciu aj v tretej osi, to jest otočenie okolo osi Z, museli by sme dáta z akcelerometra skombinovať s dátami z gyroskopu alebo magnetometra, pretože všetky akcelerometre postrádajú schopnosť detegovať rotáciu okolo vektora sily zemského gravitačného poľa [15]. Pri počítaní uhlov treba brať ohľad nato, v akom poradí/sekvencii rotácia prebieha. V našom riešení sme na výpočet uhlov použili sekvenciu xyz, ktorá bola zohľadnená pri odvodení vzorcov podľa článku Tilt Sensing Using a Three-Axis Accelerometer [15]. Vzorce odvodené pre výpočet uhlov:
[math]tg\; \phi_{xyz}\; =\; \frac{G_{py}}{G_{pz}}[/math]
[math]\phi_{xyz}\; =\; arctg\; \bigg(\frac{G_{py}}{G_{pz}}\bigg)[/math]
[math]tg\; \theta_{xyz}\; =\; \frac{-G_{px}}{G_{py}\; sin\; \phi\; +\; G_{pz}\; cos\; \phi} \; =\; \frac{-G_{px}}{\sqrt{G_{py}^2\; +\; G_{pz}^2}}[/math]
[math]\theta_{xyz}\; =\; arctg\; \Bigg(\frac{-G_{px}}{\sqrt{G_{py}^2\; +\; G_{pz}^2}}\Bigg)[/math]
kde:
- [math]\phi_{xyz}[/math] - je uhol natočenia okolo osi X v sekvencii xyz,
- [math]\theta_{xyz}[/math] - je uhol naklonenia okolo osi Y v sekvencii xyz,
- [math]G_{pi}[/math] - je hodnota zrýchlenia v príslušnej osi i.
Tieto rovnice boli následne implementované do zdrojového kódu aplikácie a použité na výpočet uhlov.
Angle_X = Math.Atan2(Converted_DataY, Converted_DataZ);
Angle_Y = Math.Atan2((-Converted_DataX),
Math.Sqrt(Math.Pow(Converted_DataY, 2)
+ Math.Pow(Converted_DataZ, 2)));
Nakoľko výsledkom týchto výpočtov je veľkosť uhlov v radiánoch, je potrevné tieto hodnotu previesť na stupne.
Rotácia 3D objektu
Vypočítané uhly natočenia v 3D priestore sa použijú pre vizualizáciu natočenia objektu v trojrozmernom priestore. Funkcia Rotate_Object
najskôr vytvorí maticu obsahujúcu údaje o natočení objektu vo všetkých troch osiach a následne aplikuje otočenie na objekt pomocou funkcie Transform
. Po otočení objektu zmení hodnotu pomocnej premennej DataProcessed
na true
, čím signalizuje aplikácii, že spracovanie dát bolo kompletné a aplikácia tak odošle ďalšiu žiadosť o čítanie hodnôt zo senzorov.
private void Rotate_Object(){
var Axis_X = new Vector3D(0, 0, 1);
var Axis_Y = new Vector3D(1, 0, 0);
var Axis_Z = new Vector3D(0, 1, 0);
Matrix3D matrix = new Matrix3D();
matrix.Rotate(new Quaternion(Axis_X, Angle_X));
matrix.Rotate(new Quaternion(Axis_Y * matrix, Angle_Y));
Dispatcher.Invoke(new Action(() =>
{
device3D.Transform = new MatrixTransform3D(matrix);
}));
DataProcessed = true;
}
Keďže získavanie hodnôt zo senzorov cez sériový port spôsobovalo zamrznutie hlavného vlákna, na ktorom beží používateľské rozhranie, museli sme pri tomto riešení využiť viacvláknové programovanie. Hlavné okno, ako aj okná s nastaveniami bežia na hlavnom vlákne a pre potrebu čítania prichádzajúcich cez sériový port bolo vytvorené nové vlákno, ktoré sa spúšťa po prijatí dát z mikrokontroléra. Na tomto pomocnom vlákne prebieha aj spracovanie nameraných údajov a pre možnosť otočenia objektu tak musel byť použitý lambda výraz, ktorý nám umožňuje asynchrónny prístup k objektu [9].