sunnuntai 4. joulukuuta 2016

Maaginen valokuppi KY-027 ja KY-004

Nämä ”maagiset valokupit” koostuvat elohopekytkimestä ja punaisesta LEDistä. Ajatuksena on (siis sarja 37 tuottajan) vuorotellen kirkastaa ja himmentää näitä kahta LEDiä. Minun on vaikeata nähdä siinä mitään maagista. Ajattelinkin ensin hyljätä näiden yksiköiden käytön. Sitten keksin, että jos kiinnitän nämä heiluriin, niin silloin valot voisivat keikkua puolelta toiselle ja kirkastua kohti ääriasentoa. Kuulostaa tosi yksinkertaiselta. Onneksi en hylännyt, sillä edessä oli vaikeuksia, eli nykykielellä: projekti oli varsin haastava.

Etualalla käynnistyspainike
Tämä olisikin ohjelmallisen sovelluksen paikka, eikä niinkään näiden komponenttien esittely. Ohjelman käynnityessä pitää mitata heilahdusajan puolikas (aika lepotilasta ääriasentoon ja takaisin), puolittaa se ja muuntaa analogilähtöön (PWM = pulssin leveysmodulaatio) LEDien kirkkausignaaliksi. Ihan hyvää ohjelmointihaastetta.

Tätä voisi kehitellä eteenpäinkin: voisi tilastoida heilunnan vakautta lämpötilan ja kosteuden suhteen. Siitä voisi tehdä kellon sijoittamalla heiluriin magneetin, mikä saisi Arduinon ohjaaman sähkömagneetin antamia potkuja (vetää puoleensa erinapaiset ja työntävät samannapaiset) kompensoimaan kitkaa, johtojen jäykkyyttä ja imanvastusta. Ja mitä kaikkea muutakin? Tämä heiluri jaksoi heilua itskseen noin 8 minuuttia.

Elementtien kytkennät
Kun mittasin näitä komponetteja (KY-027) huomasin taas epämääräisyyksiä. Juotin kaikki pisteet uudestaan ja tein testiohjelman (Ohjelma26a), jolla oli helppo testata yksikkön toiminta. Elohopeakytkin ohjaa LEDin päälle ja pois. Huomaa, että kytkimen signaali on käänteinen. Siksi ohjelmassa on huutomerkki (!) digitaaliluennan edessä (digitalWrite(Con_LED, !digitalRead(Con_Kytkin));. Tällöin kytkimen ollessa kiinni, LEDi palaa ja kytkimen ollessa auki se sammuu. Elohopeakytkimessä ei tapahdu tyypillistä millisekunnin luokkaa olevaa kytkinvärähtelyä, joten mitään varmistuslooppia ei sitä varten tarvita. Elohopeapisara (Hg) on kuitenkin hyvin elastinen ja siinä on vahva pintajännitys. Tämä merkitsee sitä, että vaikka siinä ei ole lyhytaikaista värähtelyä, niin siinä on aivan silmin nähden olevaa pomppimista. Siksi ohjelmassa pitää varmista, että ohjelma reagoi juuri oikeaan aikaan tulevaan kosketukseen tai katkoon, eikä niihin ”pomppimisen” aiheuttamiin häiriöihin.

Tällä kerralla ohjelma jakaantuu kolmeksi eri ohjelmaksi: 26a:lla testasin ainostaan elohopeapisaran ja LEDin toiminnan. Ohjelmalla 26b etsin tasapainoa elohopeakytkimien välille ja samalla mitaten heilahdusaikaa (noin 1700ms. Ohjelma mittaa puolikkaita erikseen.). Ohjelma 26c on se varsinainen tavoite, missä LEDien kirkkaus kasvaa heilurin ääriasentoihin päin ja himmenee heilurin palatessa keskiasentoon. Video havainnoi tätä paremmin (antinarduvideo26. youtube.com). Aiemmin mainitsin haastavuudesta. Lyhyitä ohjelmapätkiä syntyi; myös versiot: d, e ja f, joilla hain sopivaa tapaa saada kirkastus ja himmennys synkronoitua ajallisesti heilahdusliikkeeseen. Heilurin asennosta saadaan signaali ainoastaan heilurin pystyasennosta, kun elohopeakytkimet vaihtavat tilaansa. Tämänkin hetken luotettavuutta häiritsi piraran pomppiminen.

Analogialähtö toimii niin, että lähtösignaali vaihtelee 0:n ja 5V:n välillä siten, että päällä- ja poisolon suhde muuttuu (PWM = Pulse-Width Modulation = pulssin leveysmodulaatio). Lähdöt, jotka voivat toimia analogialähtöinä, on Arduinossa merkitty “laineella” (~).
LEDien kirkkausohjaus on toteutettu sekvenssillä Vasen kirkastuu – vasen himmenee – oikea kirkastuu – oikea himmenee jne. Sekvenssi käynnistyy painamalla painiketta, mikä sijoittaa sekvenssimuuttujaan (Seq_MittSek) arvon yksi (1). Tähän ei enää palata, vaan viimeisestä askeleesta hypätään askeleeseen 3. Painamisen jälkeen puolikas heilahdusaika voidaan tulostaa ruudulle. Tämä suoritus on askeleessa 2. Tulostus tapahtuu siis vain kerran käynnistyspainikkeen painamisen jälkeen.
Analogialähtöä ohjataan kokonaisluvulla välillä 0 .. 255 (8-bittinen muunnos). Suora ohjaus kokonaisluvulla osoittautui hankalaksi, joten päädyin muodostamaan ohjausarvon ensin liukuluvulla (float) ja sen jälkeen sijoittamaan sen kokonaislukuun lähtöjen ohjausta varten. Ennen kuin päädyin tähän ratkaisuun, kuljeskelin monenlaisia turhauttavia ja epätyydyttäviä sivupolkuja. LEDien ja heilurin synkronointi onnistui aluksi laskemalla karkeasti heilahdusajasta, kokeilemalla ja sitkeästi hakemalla sopivaa arvoa.


OHJELMA 26a
/***************************************
* Ohjelma26a
* 25.11.2016
* Modulin (KY-027) toiminnan testaus.
* Kun kytkin on kiinni, LED palaa.
**************************************/

// MÄÄRITTELYT:
const int Con_LED = 2;
const int Con_Kytkin = 3;

// ASETUKSET:
void setup(){
pinMode(Con_Kytkin, INPUT);
pinMode(Con_LED, OUTPUT);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){

digitalWrite(Con_LED, !digitalRead(Con_Kytkin));

delay(1);
} // Pääohjelma LOPPU


OHJELMA 26b
/***************************************
* Ohjelma26b
* 29.11.2016
* Modulin (KY-027) toiminnan testaus.
* Painike käynnistää mittaussekvenssin
* b-versiossa tasapainotetaan puoliskot
* säätämällä elohopeakytkimien asennot
* ja mittaamalla heilahdusajat
**************************************/

// MÄÄRITTELYT:
// I/O-määrittelyt
const int Con_LED_Vas = 5;
const int Con_Hg_Vas = 2;
boolean Bol_Hg_Vas = false;
const int Con_LED_Oik = 6;
const int Con_Hg_Oik = 3;
boolean Bol_Hg_Oik = false;
const int Con_StartPain = 4;
boolean Bol_StartPain = false;
const int Con_LED_13 = 13;

// Ajan mittauksen määrittely
unsigned long Ulo_MilliSek = 0;
unsigned long Ulo_AlkuVasen = 0;
unsigned long Ulo_AikaVasen = 0;
unsigned long Ulo_AlkuOikea = 0;
unsigned long Ulo_AikaOikea = 0;
int Seq_MittSek = 0; // Mitataan heilahdusajat

// Tulostuksen tahdistus
const int Con_PrintViive = 1000;
int Int_PrintViive = Con_PrintViive;

// ASETUKSET:
void setup(){
Serial.begin(9600);
pinMode(Con_Hg_Vas, INPUT);
pinMode(Con_LED_Vas, OUTPUT);
pinMode(Con_Hg_Oik, INPUT);
pinMode(Con_LED_Oik, OUTPUT);
pinMode(Con_StartPain, INPUT);
pinMode(Con_LED_13, OUTPUT);
}// Asetuksen loppu

// FUNKTIOT
void Fun_Tulostus(){
// Serial.print("Painike :"); Serial.println(Bol_StartPain);
// Serial.print("LEDi :"); Serial.println(Con_LED_13);
Serial.print("Vasen aika :"); Serial.println(Ulo_AikaVasen);
Serial.print("Oikean aika :"); Serial.println(Ulo_AikaOikea);
} // Tulostus loppu

// PÄÄLOOPPI
void loop(){
Ulo_MilliSek = millis(); // Luetaan sisäinen kello
// Painiketesti
Bol_StartPain = digitalRead(Con_StartPain);
digitalWrite(Con_LED_13, Bol_StartPain);

// LEDien ohjaus elohopeakytkimistä
Bol_Hg_Vas = !digitalRead(Con_Hg_Vas);
Bol_Hg_Oik = !digitalRead(Con_Hg_Oik);
digitalWrite(Con_LED_Vas, Bol_Hg_Vas);
digitalWrite(Con_LED_Oik, Bol_Hg_Oik);

// Aikojen käynnistys ja mittaus
if(Bol_StartPain == true && Seq_MittSek == 0){
Seq_MittSek = 1;
}
switch (Seq_MittSek) {
case 1: // Vasemman elohopeakytkimen odotus
if(Bol_Hg_Vas == true){
Ulo_AlkuVasen = Ulo_MilliSek;
delay(560); // Eliminoidaan pisaran pomppiminen
Seq_MittSek = 2;
}
break;
case 2: // Lasketaan vasen heilahdusaika
if(Bol_Hg_Vas == false){
Ulo_AikaVasen = Ulo_MilliSek - Ulo_AlkuVasen;
Seq_MittSek = 3;
}
break;
case 3: // Käynnistetään oikean heilahdusaika
if(Bol_Hg_Oik == true){
Ulo_AlkuOikea = Ulo_MilliSek;
delay(560); // Eliminoidaan pisaran pomppiminen
Seq_MittSek = 4;
}
break;
case 4: // Lasketaan oikea helahdusaika
if(Bol_Hg_Oik == false){
Ulo_AikaOikea = Ulo_MilliSek - Ulo_AlkuOikea;
Seq_MittSek = 5;
}
break;
case 5:
Fun_Tulostus();
Seq_MittSek =  0;  //jos haluaa vain kertatulostuksen
break;                    // uusi painaminen = seuraava tulostus
}

Int_PrintViive--;
if(Int_PrintViive == 0){
Fun_Tulostus();
Int_PrintViive = Con_PrintViive;
} // Tulostuskutsu loppu
delay(1);
} // Pääohjelma LOPPU

OHJELMA 26c
/***************************************
* Ohjelma26c
* 29.11.2016
* Modulin (KY-027) toiminnan testaus.
* c-versiossa muutetaan LEDien kirkkautta
* analogialähtöjen avulla (PWM)
**************************************/

// MÄÄRITTELYT:
// I/O-määrittelyt
const int Con_LED_Vas = 5;
const int Con_Hg_Vas = 2;
int Int_LED_Ohjaus = 0;
float Flo_LED_Ohjaus = 0.0;
float Flo_Muutos = 0.58;
boolean Bol_Hg_Vas = false;
const int Con_LED_Oik = 6;
const int Con_Hg_Oik = 3;
boolean Bol_Hg_Oik = false;
const int Con_StartPain = 4;
boolean Bol_StartPain = false;
const int Con_LED_13 = 13;

// Ajan mittauksen määrittely
unsigned long Ulo_MilliSek = 0;
unsigned long Ulo_AlkuVasen = 0;
unsigned long Ulo_AikaVasen = 0;
int Seq_MittSek = 0; // LEDien kirkkauden ohjaus

// ASETUKSET:
void setup(){
Serial.begin(9600);
pinMode(Con_Hg_Vas, INPUT);
pinMode(Con_Hg_Oik, INPUT);
pinMode(Con_StartPain, INPUT);
pinMode(Con_LED_13, OUTPUT);
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){
Ulo_MilliSek = millis(); // Luetaan sisäinen kello
// Painiketesti
Bol_StartPain = digitalRead(Con_StartPain);
digitalWrite(Con_LED_13, Bol_StartPain);

// LEDien ohjaus elohopeakytkimistä
Bol_Hg_Vas = !digitalRead(Con_Hg_Vas);
Bol_Hg_Oik = !digitalRead(Con_Hg_Oik);

// Aikojen käynnistys ja mittaus
if(Bol_StartPain == true && Seq_MittSek == 0){
Seq_MittSek = 1;
}
switch (Seq_MittSek) {
case 1: // Vasemman elohopeakytkimen odotus
if(Bol_Hg_Vas == true ){
Ulo_AlkuVasen = Ulo_MilliSek;
delay(560); // Eliminoidaan pisaran pomppiminen
Seq_MittSek = 2;}
break;
case 2: // Lasketaan vasen heilahdusaika
if(Bol_Hg_Vas == false){
Ulo_AikaVasen = Ulo_MilliSek - Ulo_AlkuVasen;
Serial.print("Heilahdusaika :"); Serial.println(Ulo_AikaVasen);
Seq_MittSek = 3;}
break;
case 3: // Odotetaan uutta heilahdusta vasemmalle
Int_LED_Ohjaus = 0;
if(Bol_Hg_Vas == true ){
Seq_MittSek = 4;}
break;
case 4: // Vasen LED kirkastuu
analogWrite(Con_LED_Vas, Int_LED_Ohjaus);
Flo_LED_Ohjaus = Flo_LED_Ohjaus + Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
if(Int_LED_Ohjaus == 255){
Seq_MittSek = 5;}
break;
case 5: // Vasen LED himmenee
Flo_LED_Ohjaus = Flo_LED_Ohjaus - Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
analogWrite(Con_LED_Vas, Int_LED_Ohjaus);
if(Int_LED_Ohjaus == 0 && Bol_Hg_Oik == true ){
Seq_MittSek = 6;}
break;
case 6: // Oikea LED kirkastuu
analogWrite(Con_LED_Oik, Int_LED_Ohjaus);
Flo_LED_Ohjaus = Flo_LED_Ohjaus + Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
if(Int_LED_Ohjaus == 255){
Seq_MittSek = 7;}
break;
case 7: // Oikea LED himmenee
Flo_LED_Ohjaus = Flo_LED_Ohjaus - Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
analogWrite(Con_LED_Oik, Int_LED_Ohjaus);
if(Int_LED_Ohjaus == 0 && Bol_Hg_Vas == true ){
Seq_MittSek = 3;}
break;
} // Sekvenssi loppu
delay(1);
} // Pääohjelma LOPPU

Ei kommentteja:

Lähetä kommentti