tiistai 20. maaliskuuta 2018

Leikkiminen Arduinojen ja micro:bitien kanssa jatkuu...

Tänään paneuduin pitkästä aikaa virtapiirien kytkentäkuvien piirtämiseen ja huomasin, että aikaisemmin käyttämäni circuits.io:n Electronics Lab olikin vaihtunut Tinkercad:ksi. No, hyvin näytti tämänkin toimivan. Koodi oli helppoa tehdä blokkieditorilla ja simulointi toimi mainiosti. Uutta oli myös se, että johtimet sai piirrettyä hienosti kaareviksi. Simuloinnin lisäksi koodin saa myös ladattua omalle koneelle ArduinoCC-tiedostona! Eipä hullumpaa.

Tässä ensimmäinen kokeiluni, servomoottorin ohjaaminen potentiometrillä. Simulaation käynnistämisen jälkeen tartu hiirellä potentiometriin ja liikuttele sitä niin saat servon kääntymään. Jos haluat tutkia koodia, sen saa näkyviin valitsemalla "Code".


Tinkercadillä piirretty kytkentäkuva servomoottorin ohjaamisesta potentiometrillä 

Tinkercadillä voi myös ohjelmoida ja ladata koodin ArduinoCC-tiedostona
Tämän näköistä koodia tästä generoitui:

#include <Servo.h>

Servo servo_3;

void setup()
{
  pinMode(A0, INPUT);
  servo_3.attach(3);

}

void loop()
{
  servo_3.write(map(analogRead(A0), 0, 1023, 0, 180));
  delay(100); // Wait for 100 millisecond(s)
}

Tässä vielä kuva kytkennästä:

Arduino kytkettynä potentiometriin ja servomoottorin
Vastaava toiminta micro:bit:illä ei toiminut aivan näin hyvin. Simulaatioon ei voi itse lisätä komponentteja, servo kyllä ilmestyy siihen automaattisesti kun koodiin valitsee servoblokin, potentiometriä ei voi lisätä mutta sitä voi mallintaa klikkailemalla P1-pinniä. Ensimmäinen versio koodista ei toiminut. Ilmeisesti vika on siinä, että koska JSBlocks ei tue liukulukuja jakolasku pyöristyy nollaksi... 

Hyvältä näyttää mutta ei toimi...

Kun laskujärjestyksen muuttaa niin, että kertolasku suoritetaan ensin, homma lähtee toimimaan. Aika kinkkistä...

Tämä versio koodista toimii 

Tässä linkki projektiin. Microbit:iin ladattuna koodi ei kuitenkaan toimi yhtä hyvin kuin Arduino:ssa, servo pörisi ja nyki epäilyttävästi. Tämä johtuu micro:bit:in alemmasta käyttöjännitteestä (Arduino 5V, micro:bit 3,3V). 

Tässä vielä vertailun vuoksi sama koodi ohjelmoituna C++:lla ja mbed:llä:

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    uBit.init();
    
    while(1){
    int potikka = uBit.io.P1.getAnalogValue(); //P1: 0-1024 
    int moottori = (int(potikka/1024.0*180));
    uBit.io.P0.setAnalogValue(moottori);  //P0: 0-180    
    uBit.sleep(10);
    }
}

Myös mbed:llä ohjelmoidessa kokonaislukujen jakolaskun kanssa pitää olla tarkkana ja muistaa muuttaa ainakin toinen liukuluvuksi (vrt. 1024.0 yllä olevassa koodissa) ettei tulos pyöristy tässäkin nollaan. 

Tämän kytkennän sai toimimaan ilman kondensaattoria Arduinon kanssa mutta micro:bit:illä ei (moottori jämähti välillä paikoilleen). Kondensaattorin tarkoitus on tässä tasailla moottorin käynnistämisen aiheuttamia virtapiikkejä, ja ilmeisesti alemmalla käyttöjännitteellä tasaaminen auttaa pitämään moottorin käynnissä paremmin. micro:bit:in kanssa pitäisi ilmeisestikin käyttää ulkoista jännitelähdettä servolle, ja se taas johtaisi paljon monimutkaisempaan kytkentään...

micro:bit kytkettynä potentiometriin ja servomoottoriin

perjantai 2. maaliskuuta 2018

Buzzer-ongelman ratkaisu eli jälleen kerran lisää micro:bit:in ohjelmointia C++:lla mbed:in kautta

Ja pienen mutkan jälkeen sain summerinkin (piezo buzzer) soittamaan melodioita C++:lla mbedin kautta. Tähän tarvittiin PWM_tone_library. Kirjaston asentaminen mbed-ympäristössä on helppoa, riittää että menee kirjaston sivulle ja painaa esimerkkiohjelman kohdalla "import program". Tämä tekee uuden projektin mbed-ympäristöön ja imaisee mukaansa kaikki esimerkkiohjelman vaatimat kirjastot (tässä mukaan tulee siis PWM_tone_library sekä mbed-kirjasto).

Piezo buzzer -kirjaston asennus mbed:issä
Jotta tämän saa toimimaan micro:bit:in kanssa, projektiin pitää kopioida myös MicroBit - kirjasto (sen voi hakea jostain vanhasta projektista copy-paste:lla). 

Projektissa pitää olla microbit, mbed ja PWM_Tone_Library
Malliohjelmaa pitää muokata kahdesta kohtaa:
  1. lisää MicroBit - kirjasto #include "MicroBit.h"
  2. Vaihda "D5":n (pinnin nimi) tilalle käyttämäsi analogiapinni esim.  MICROBIT_PIN_P1
Ja sitten vain kiinnittämään summeria pinnin P1 ja GND:n väliin ja lataamaan ohjelmaa micro:bit:iin. Jos haluaa samalla tutkia ledinäytöllä missä mennään lisäsin tähän koodiin pieniä tulosteita (jotka asynkronisen toiminnan ansiosta toimivat samaan aikaan kuin melodia):

#include "mbed.h"
#include "MicroBit.h"
#include "pwm_tone.h"

MicroBit uBit;

PwmOut Buzzer(MICROBIT_PIN_P1);

float C_3 = 1000000/Do3,
       Cs_3 = 1000000/Do3s,
       D_3 = 1000000/Re3,
       Ds_3 = 1000000/Re3s,
       E_3 = 1000000/Mi3,
       F_3 = 1000000/Fa3,
       Fs_3 = 1000000/Fa3s,
       G_3 = 1000000/So3,
       Gs_3 = 1000000/So3s,
       A_3 = 1000000/La3,
       As_3 = 1000000/La3s,
       B_3 = 1000000/Ti3,
       C_4 = 1000000/Do4,
       Cs_4 = 1000000/Do4s,
       D_4 = 1000000/Re4,
       Ds_4 = 1000000/Re4s,
       E_4 = 1000000/Mi4,
       F_4 = 1000000/Fa4,
       Fs_4 = 1000000/Fa4s,
       G_4 = 1000000/So4,
       Gs_4 = 1000000/So4s,
       A_4 = 1000000/La4,
       As_4 = 1000000/La4s,
       B_4 = 1000000/Ti4,
       C_5 = 1000000/Do5,
       Cs_5 = 1000000/Do5s,
       D_5 = 1000000/Re5,
       Ds_5 = 1000000/Re5s,
       E_5 = 1000000/Mi5,
       F_5 = 1000000/Fa5,
       Fs_5 = 1000000/Fa5s,
       G_5 = 1000000/So5,
       Gs_5 = 1000000/So5s,
       A_5 = 1000000/La5,
       As_5 = 1000000/La5s,
       B_5 = 1000000/Ti5;

int tones[] = {E_4, D_4, C_4, D_4, E_4, E_4, E_4, 0, D_4, D_4, D_4, 0, E_4, G_4, G_4, 0, 
                             E_4, D_4, C_4, D_4, E_4, E_4, E_4, 0, D_4, D_4, E_4, D_4, C_4, 0, 0, 0};
int tones_num = 32;

int main(void)
{
    uBit.init();
    uBit.display.printAsync('C');
    Tune(Buzzer, C_4, 4);  //4 Octave C beat 4/16
    wait_ms(250);
    uBit.display.printAsync('D');
    Tune(Buzzer, D_4, 4);  //4 Octave D beat 4/16
    wait_ms(250);
    uBit.display.printAsync('E');
    Tune(Buzzer, E_4, 4);  //4 Octave E beat 4/16
    wait_ms(250);
    
    int i;
    
    uBit.display.scrollAsync("melody");
    
    for(i=0; i<tones_num; i++)
    {
        Auto_tunes(Buzzer, tones[i], 4); // Auto performance
        Stop_tunes(Buzzer);
    }
}

Eihän tämä lopulta vaikeaa ollut mutta sitäkin palkitsevampaa kun tuo pieni melodia lopulta tuli ulos :-) Se mitä tässä tarvittiin oli kirjasto, joka osaa tehdä PWM:ää (Pulse Width Modulation) analogiapinnille (PwmOut-rajapinta mbed-kirjastossa), tietoa eri sävelten taajuuksista (pwm_tone.h-tiedostossa). Esimerkkikoodissa muunnettiin sävelen taajuus värähdysajaksi (värähdysaika on taajuuden käänteisluku) mikrosekunneissa (µs). Esim. PWM värähdysaika 440Hz sävelelle on 1000000/440. Ja tuolla jaksonajalla vaihteleva jännite saa pietsoelementin sisällä olevan metallilevyn tuottamaan jotakuinkin yksiviivaista a:ta vastaavaa ääntä. Kaikkea sitä oppii kun näiden kanssa pelaa... 

Ja tilanne mbed-ArduinoCC micro:bit:in osalta on nyt virallisesti 2-0.

micro:bit:in ohjelmointia ArduinoCC:llä

Koska seinä nousi pystyyn summerin soitossa mbed:in kanssa, päätin kokeilla toista C/C++ tyylistä ohjelmointiympäristöä ArduinoCC:tä micro:bit:in ohjelmointiin. micro:bit ei ole suoraan tuettu ArduinoCC:ssä (korttivalikosta ei löydy heti heittämällä micro:bit:iä), mutta sen voi ladata helposti. Valitse Tiedosto -> Asetukset ja lisää kohtaan "Additional Boards Managers URL"-kohtaan: https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json ja valitse ok. Tämän jälkeen avaa Työkalut -> Kortti -> Boards manager ja kirjoita hakukentään nRF5, valitse Nordic Semiconductors by Sandeep Mistry ja paina "asenna". Nyt voit käydä valitsemassa Työkalut -> Kortti -listasta micro:bit:in, muista myös valita oikea COM-portti kuten Arduinonkin kanssa. Valitse vielä Työkalut -> Softdevice valikosta "S110". Nyt sinulla on yhteys micro:bit:iin ja voit ohjelmoida sitä kuin Arduino:a. Koodi latautuu suoraan micro:bit:iin, eli sitä ei tarvitse erikseen siirtää kuten mbed:in tai JS Blocks:in kanssa.

micro:bit - tuen lisääminen ArduinoCC:hen (ensimmäinen vaihe)
micro:bit - tuen lisääminen ArduinoCC:hen (toinen vaihe)
Tässä pieni koodin pätkä, jossa ohjataan ledinäytön vasemman yläkulman lediä. Kun A-napista painetaan ledi alkaa vilkkua, kun napista B painetaan se pimenee ja kun mitään ei paineta, se palaa koko ajan.

const int COL1 = 3;
const int LED = 26;
const int buttonA = 5;     // the number of the pushbutton pin
const int buttonB = 11;    // the number of the pushbutton pin

void setup() {
  pinMode(COL1, OUTPUT);
  digitalWrite(COL1, LOW);
  pinMode(LED, OUTPUT);
  pinMode(buttonA, INPUT);  
  pinMode(buttonB, INPUT);   
}

void loop() {
  if (! digitalRead(buttonA)) {
    digitalWrite(LED, HIGH);
    delay(500);
    digitalWrite(LED, LOW);
    delay(500);
  } else if (! digitalRead(buttonB)) {
    digitalWrite(LED, LOW);
  } else {
    digitalWrite(LED, HIGH);
    }

  delay(10);
} 

Koska ledi näytön 25 lediä ohjataan 12 pinnillä oman logiikkansa mukaisesti (ledit multipleksattu, katso lisätietoa), sen käyttäminen ilman apukirjastoa on hieman sekavaa ja työlästä. Onneksi näytön ohjaamiseen on tarjolla kirjasto ja sen asentaminen onnistuu yhtä vaivattomasti kuin edellinenkin laajennos. Lataa github:ista seuraava zip-tietosto:  https://github.com/ht-deko/microbit_Screen/archive/master.zip ja avaa valikosta Sketsi -> Sisällytä kirjasto -> Tuo .ZIP kirjasto.

Kirjaston asentaminen ArduinoCC:hen
Valitse lataamasi .ZIP - tiedosto, jonka jälkeen voit lisätä sen koodiisi valikosta Sketsi -> Sisällytä kirjasto -> microbit_Screen-master. Tämän jälkeen koodiisi ilmestyy seuraava rivi koodia, joka ottaa kirjaston käytöön:

#include <microbit_Screen.h>

Tämän kirjaston avulla ledinäytölle saa vaivattomasti tekstiä, esimerkkinä se kuuluisa "Hello World!":

#include <microbit_Screen.h>

void setup() {
  SCREEN.begin();
}

void loop() {
  SCREEN.showString("Hello,World!");    
}

Vielä täytyy testata miten sen potentiometrillä ohjattavan RGB:n ledin ja summerin koodi oikein ArduinoCC:llä taittuisi... ja eihän se sitten lopulta toiminut. tone - funktiota ei löytynyt micro:bit:ille ja muutenkin koodin toiminta "pätki" eli ledi ei reagoinut reaaliajassa potentiometrin pyöritykseen kuten mbed:in kanssa. 1-0 mbed:ille ja 0-0 summerin käytössä :-)

Tässä kuitenkin koodi:

#include <microbit_Screen.h>

const int POTIKKA = 0;
const int SUMMERI = 1;
const int RGB_R = 8;
const int RGB_B = 3;
const int RGB_G = 16;

void setup() {
  SCREEN.begin();
  pinMode(RGB_R, OUTPUT);
  pinMode(RGB_B, OUTPUT); 
  pinMode(RGB_G, OUTPUT); 
  pinMode(SUMMERI, OUTPUT);
  pinMode(POTIKKA, INPUT);
}

void loop() {
    int sensorvalue = analogRead(POTIKKA);   // P1: 0 - 1024 
    SCREEN.showString(String(sensorvalue));
  //    tone(SUMMERI, sensorvalue);
    if(sensorvalue <= 340){
        digitalWrite(RGB_R, HIGH);
        digitalWrite(RGB_B, LOW);
        digitalWrite(RGB_G, LOW);        
        } else if(sensorvalue > 340 && sensorvalue <=680){
          digitalWrite(RGB_R, LOW);
          digitalWrite(RGB_B, HIGH);
          digitalWrite(RGB_G, LOW);
          } else {
            digitalWrite(RGB_R, LOW);
            digitalWrite(RGB_B, LOW);
            digitalWrite(RGB_G, HIGH);
            }
  delay(10);
}

Testikytkentä: potentiometri, RGB-ledi, summeri ja ledinäyttö

torstai 1. maaliskuuta 2018

Vieläkin lisää micro:bit:in ohjelmointia C++:llä mbed:in kautta

Kuten aika usein, nälkä kasvaa syödessä. Kolmas päivä putkeen micro:bit:in ja C++:n kanssa (no onneksi on loma).

Tänään otin esille Kitronik breakout boardin, jonka avulla pääsee eroon hauenleukajohdoista ja samalla saa käyttöönsä myös ne pienemmät pinnit, joihin hauenleukaa ei edes saa kiinni.

Ensimmäiseksi tein digitaalisen lämpömittarin, joka näyttää lämpötilalukemaa ledinäytöllä. micro:bit:issä on myös sisäinen lämpömittari, mutta sen lämpötila kuvaa lähinnä piirilevyn lämpötilaa, ei huoneen lämpötilaa. Testauksessa myön paristokotelo, jonka avulla laitteen voi irrottaa tietokoneesta. Tällainen kytkentä siitä tuli:

Kitronik breakout board, lämpötilasensori LM35 ja paristokotelo
Ja koodina tällainen:

#include "MicroBit.h"

MicroBit uBit;

float rawToTemp(int x){
  float temp = 0;
  temp = (3.0*x*100)/1024;
  return temp;
}    

int main()
{
    uBit.init();
    
    while(1){
    int sensorvalue = uBit.io.P0.getAnalogValue();   
    int t = static_cast<int>(rawToTemp(sensorvalue));
    uBit.display.scrollAsync(t);
    uBit.sleep(2);
    }
}

Aluksi idea oli kytkeä mukaan myös summeri (buzzer) mutta käytetyssä rajapinnassa ei ollutkaan tukea äänille, ja digitaalinen on/off sai aikaan vain napsumista ja analoginen jännitteen säätö vaimeaa pörinää. Lämpötilan vaihtuminen oli myös hyvin jähmeää, puhaltelemalla se ei meinannut nousta ollenkaan ja pakkasessakin lämpötila laski hyvin hitaasti (ei alle +6 asteen, vaikka ulkona oli -15 astetta). Ei kovin optimaalinen mittari siis.

Seuraava kokeilu toimikin jo paremmin: RGB-ledin ohjaaminen potentiometrillä. Kytkin potentiometrin pinniin P0 ja RGB-ledin pinneihin P1, P2 ja P16. Koska halusin näyttää  potentiometrin antaman lukeman ledinäyttöä, käyttööni ei jäänyt yhtään vapaata analogiapinniä (ovat ledinäytön kanssa yhteisiä), joten jouduin tyytymään digitaaliseen toimintaan (pinni P16 on vain digitaalinen), ja tämä rajoitti hieman RGB-ledin käyttöä. Ohjelma toimii niin, että pienillä potentiometrin arvoilla ledi näyttää punaista, keskivälillä vihreä ja suurilla arvoilla sinistä valoa.

Tässä koodi:

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    uBit.init();
    
    while(1){
    int sensorvalue = uBit.io.P0.getAnalogValue();
    uBit.display.scrollAsync(sensorvalue);
    if(sensorvalue <= 340){
        uBit.io.P1.setDigitalValue(1);
        uBit.io.P2.setDigitalValue(0);
        uBit.io.P16.setDigitalValue(0);
        } else if(sensorvalue > 340 && sensorvalue <=680){
            uBit.io.P1.setDigitalValue(0);
            uBit.io.P2.setDigitalValue(1);  
            uBit.io.P16.setDigitalValue(0);
            } else {
                uBit.io.P1.setDigitalValue(0);
                uBit.io.P2.setDigitalValue(0);   
                uBit.io.P16.setDigitalValue(1);
                }
        }
}

RGB-ledi punainen

RGB-ledi vihreä

RGB-ledi sininen

Breakout board on kyllä kätevä verrattuna hauenleukoihin mutta varsinaisesti sitä tarvitsee vasta sitten kun GPIO-pinnejä tarvitaan enemmän kuin kolme. micro:bit:in pinnien käyttö on hieman sekavampaa kuin Arduinossa mutta tämän kuvan ja taulukon avulla siitäkin saa tolkkua.

PS: Ja sen summerin saa soimaan JS Blocks micro:bit:in avulla 440Hz:n taajuudella tällä koodilla (ääni on niin hiljainen, että mikään varashälytin tämä ei ole :-)):