...
- Mallinna liikennevalot UML-tilakonekaaviona esim käyttäen kaavionpiirto-ohjelmaa. Voit olettaa, että tilakoneeseen tulee tapahtuma "30 sekuntia kulunut" jolloin valoja voi vaihtaa. Voit halutessasi mallintaa myös liikennevalojen välitilat joissa keltainen valo on päällä. http://en.wikipedia.org/wiki/UML_state_machine
- Toteuta tilakone switch-case rakenteella. Voit käyttää koodin kirjoittamiseen esimerkiksi http://ideone.com/ -ympäristöä. Kieleksi voi valita esim. C++11
Esimerkki tällä tavalla toteutetusta tilakoneesta löytyy sivulta Yksinkertainen Caps Lock -tilakonemalli tai osoitteesta http://en.wikipedia.org/wiki/Event-driven_finite-state_machine - Tee Qt Creatorissa uusi käyttöliittymäsovellus, lisää käyttöliittymään aluksi painikeet tilakoneen tilojen vaihtamiseksi, ja tekstikentät joissa lukee missä tiloissa eri liikennevalot milloinkin ovat.
- Lisää tilakoneeseesi QTimer-ajastin, joka vaihtaa tilakoneen tiloja
- Mallinna kerrostalon hissi UML-tilakonekaaviona esim käyttäen kaavionpiirto-ohjelmaa. Sisällytä toiminnallisuuteen ainakin perustoiminnallisuus eli esim. kaikkien kerrosten painikkeet ja näytöt, jotka kertovat hissin tilasta.
- (Valinnainen lisätehtävä) Lisää tilakoneeseen myös ovien sensorit ja ajastin oven sulkeutumiselle, sekä mahdollisuus painaa useamman kerroksen painikkeita siten, että hissi muistaa mennä niihin kaikkiin yksi kerrallaan.
- Toteuta tilakone switch-case rakenteella.
Esimerkki tällä tavalla toteutetusta tilakoneesta löytyy mm. osoitteesta http://en.wikipedia.org/wiki/Event-driven_finite-state_machine - Tee Qt Creatorissa uusi käyttöliittymäsovellus, joka simuloi hissin toimintaa.
- Toteuta aikaisemman tehtävän liikennevalot Qt:n QStateMachine:na. Esimerkki Qt:n tilakoneen käytöstä löytyy sivulta Erittäin yksinkertaiset liikennevalot Qt-tilakoneena. Kytke esimerkkiin QTimer-ajastin, joka pyörittää liikennevaloja painikkeen sijaan.
- Toteuta aikaisemman tehtävän hissi Qt:n QStateMachine:na.
- Toteuta Qt:n QStateMachinella liikennevalo-tilakone, jossa on mallinnettuna sekä yksittäisen liikennevalon, että koko risteyksen tilanne. Tarvitset tähän alitilakoneita.
2. Tehtäväsarja
- Tee Qt:llä ohjelma, jossa lasket yhteen kaksi kahdeksanbittistä etumerkillistä lukua, käytä tietotyyppiä qint8. Tee tarkastukset, etteivät luvut pääse "vuotamaan yli" ja estä ylivuoto saturoimalla luvut tarvittaessa ala-ja ylärajalle.
Tee Qt:lla syöttöruudut, laske painikkeella ja tulosta uuteen tekstiruutuun. Käytä validatoria Validator, double int jne. luettavien arvojen hyväksyntään.
- Tee Qt:llä ohjelma, jossa teet JA-, TAI- Ehdoton TAI, JA-EI, TAI-EI operaatiot kahden bool-tyyppisen luvunvälillä.
- Tee edellinen tehtävä Qt:n tyyppillä quint8 .
- Tee ohjelma, joka nollaa bitit 4 ja 5 antamastasi 8 bittisestä luvusta (kokeile tyyppejä quint8, qint8 ja unsigned char) ja tulostaa arvon.
- Tee ohjelma, joka asettaa bitit 4 ja 5 arvoon yksi 8 bittisestä luvusta.
- Tee ohjelma, joka vaihtaa bittien 4 ja 5 arvot vastakkaisiksi antamastasi 8 bittisestä luvusta. Kutsu funktiota kaksi kertaa ja tarkasta saitko takaisin alkuperäisen luvun.
- Kahdessa 8 bittisessä luvussa on merkitsevänä osana molemmissa neljä vähinten merkitsevää bittiä. Yhdistä luvut yhteen kahdeksan bittiseen lukuun siten että ensimmäinen luku on neljässä vähiten merkitsevässä bitissä ja toinen neljässä eniten merkitsevässä bitissä. Loogiset operaatiot kahdeksanbittisillä luvuilla
- Vaihda 16 bittisen luvun vähiten merkitsevä ja eniten merkitsevä tavu keskenään.
- Testaa sizeof funktion toimintaa ja tulosta näytölle char, short, int, long ja long long tyyppien koko.
- Lue Checkboxeista arvot 8-bittiseen kokonaislukuun (quint8), näytä luku lcd-ikkunassa ja pura arvot takaisin toisiin checkboxeihin.
- CAN-väylässä viesti lähetetään enimmillään 64 bitin ryhmissä. Suunnittele ja toteuta viesti, joka koostuu kahdesta 8-bittisestä etumerkillisestä lämpötilaviestistä, 16-bittisestä etumerkittömästä pyörimisnopeusviestistä, 32-bittisestä asemaviestistä. Tee ohjelma, joka laittaa viestit CAN-viestiin em.järjestyksessä. Humioita! Vaikka lämpötila-arvot luetaan etumerkillisinä, ne kannattaa sijoitaa 64-bittiseen viestiin etumerkittöminä, jos muutat negatiivisen qint8 arvon (kahden komplementin) qint64 arvoksi, niin "etumerkki bitti" menee bittiin numero 64 ja muunnoksesta tulee susi koko viestin kannalta. Kannattaa aetaan break point muunnosten eteen ja asettaa oikealla näkyvä muuttujaikkuna binaarimuotoon, jotta sijoitukset ovat parhaiten nähtävissä ja tämän jälkeen ajaa koodia rivi kerrallaan.
- Tee ohjelma, joka purkaa viestit CAN-viestistä takaisin muuttujiin.
- Tee ohjelma, joka laskee juoksevaa keskiarvoa perättäin annetusta luvusta. Laske keskiarvo viidestä viimeksi annetusta luvusta ja näytä se Qt:n "lcd-näytössä".
- Tee tilakoneen switch...case valintarakenne ideaa hyväksi käyttäen jalankulkijoille liikennevalot. a. Tee ensin tehtävälle vaatimusten määrittely ja piirrä sitten jollain piirto-ohjelmalla tilakone, jossa määrittelet jokaiselle tilalle entry, do ja exit ehdot. b. Tee tilakonemalli alo-ohjatulle risteykselle, jossa on myös risteävää ajoneuvoliikennettä.
- Toteuta suunnittelemallesi ohjelmalle Qt:llä toteutus.
- Tee tilakonemalli manipulaattorille. Manipulaattori nostaa imukupin avulla laatikon liukuhihnalta ja laskee sen toiselle hihnalle. Tarraimena käytetään imukuppia, jossa on painekytkin tunnistmassa kappaletta.
- Lisää tilakonemalliin ehjän kappaleen tunnistus. Tieto, että kappale on ehjä saadaan, kun kapplae on nostettu ylös. Ehjät kappaleet viedään asemaan A ja virheelliset asemaan B
- Tee, edellisen tehtävän tilakonemallille toteutus Qt:llä.
Testaa alla esitetyn luokan funktiot.
Code Block language cpp collapse true #ifndef SRMATH_H #define SRMATH_H #include <QObject> class Srmath : public QObject { Q_OBJECT public: explicit Srmath(QObject *parent = 0); double Abs(double in){if(in<0.0)return in*(-1.0); else return in;} qint8 Abs(qint8 in){if(in<0)return in*(-1); else return in;} qint16 Abs(qint16 in){if(in<0)return in*(-1); else return in;} qint32 Abs(qint32 in){if(in<0)return in*(-1); else return in;} qint8 isPositive(qint8 in){if(in<0)return -1; else return 1;} qint16 isPositive(qint16 in){if(in<0)return (-1); else return 1;} qint32 isPositive(qint32 in){if(in<0)return (-1); else return 1;} double isPositive(double in){if(in<0.0)return (-1.0); else return 1.0;} double Saturate(double in,double limit); bool AbsSmaller(double input,double limit); bool AbsLarger(double input,double limit); bool AbsLargerAndSameSign(double input,double limit); double RaiseAbsLimit(double input,double *limit); double LowerAbsLimit(double input,double *limit); bool InsideOfLimits(double input1,double input2, double limitPercent); double CalcAverage(double input,quint8 length); private: double AvrVector[10]; quint8 PointInAvrVector; double Sum; quint8 counter; }; #endif // SRMATH_H #include "srmath.h" Srmath::Srmath(QObject *parent) : QObject(parent) { PointInAvrVector=0; } double Srmath::Saturate(double in,double limit) { if(in>limit){ return limit; } else if(in<-limit){ return -limit; } else return in; } bool Srmath::AbsSmaller(double input,double limit) { if(Abs(input)<Abs(limit))return true; else return false; } bool Srmath::AbsLarger(double input,double limit) { if(Abs(input)>Abs(limit))return true; else return false; } // when input is abs greater than limit and same sign bool Srmath::AbsLargerAndSameSign(double input,double limit) { if ((Abs(input) > Abs(limit))&&((input*limit)>=0)) return true; else return false; } //! if input is absolute greater than limit, function raises limit double Srmath::RaiseAbsLimit(double input,double *limit) { if(Abs(input)>Abs(*limit)){ *limit=Abs(input); } return *limit; } //! if input is absolute smaller than limit, function sets down limit double Srmath::LowerAbsLimit(double input,double *limit) { if(Abs(input)<Abs(*limit)){ *limit=Abs(input); } return *limit; } bool Srmath::InsideOfLimits(double input1,double input2, double limitPercent) { double limit=limitPercent/100.0; if(input1<input2*(1.0+limit) &&input1>input2*(1.0-limit)){ return true; } else return false; } double Srmath::CalcAverage(double input,quint8 length) { Sum=0; if(length>10)length=10; AvrVector[PointInAvrVector]=input; PointInAvrVector++; if(PointInAvrVector>(length-1))PointInAvrVector=0; for(counter=0;counter<length;counter++){ Sum+=AvrVector[counter]; } return Sum/length; }
- Tee tehtävät 11 ja 12 käyttäen udp-protokollaa ja tee lähettävä ja vastaanottava osa omiin ohjelmiinsa. kts. Tiedonvälitys udp-protokollalla
- Tässä tehtävässä testataan Qt:n säikeistystä. Esimerkki säikeistyksestä
- Tee moottorinohjaukselle luokka-arkkitehtuuri, jossa koostavana luokkana on luokka Moottori ja aliluokkana PAsuihkutus. Koosta se vielä neljästä Suutin oliosta (käytä QVector muuttujaa). Peri luokka Moottori BeMoottori luokkaan. Koosta Dialog luokka BeMoottorista.
- Tee moottorille start painike ja laita dialogiin suuttimia varten radioButtonit, jotika välkkyvät suutinten aukeamisen tahtiin. Käytä QTimer oliota toiminnan tahdistamiseen. Tee kaasupoljin vaikka Silerilla ja kiihdytä ajastimen tahtia Sliderin avulla.
- Tee BeMoottori luokkaan Sytytys luokka ja keksi sille tekemistä.
- Tee luokkahierarkia koneenohjaukselle. Ylimpänä rakenteessa on luokka Kone, joka koostaa luokan toimilaite (QVector) ja toimilaite koostaa anturit, joita voi olla n. kappaletta.
- Tee broadcast server ja clien ohjelmista versiot, jossa dialogit tehdään graafisella editorille.
- Lisää edellisen tehtävän ohjelmiin kieliversiointi. (Suomi ja Englanti)
- Tee broadcast serveristä versio, jossa palveloin lähettää lämpötilaa. Simuloi lämpötilaa liukupalkilla. Muuta asiakas lukemaan ko. arvoa.
- Tutustu Fortune Client esimerkkiin. Tee esimerkin pohjalta uusi ohjelma, jossa dialogin ja verkon toiminnallisuudet ovat omissa luokissaan. Eli tee luokat Dialog ja Client. Toteuta esimerkki siten, että funktiot, jotka käsittelevät viestejä ovat askNewMessage ja readMessage (Dialog luokassa). Tee napit Connect, Ask Message, Read Message ja End.
- Kopioi Client luokkaan esimerkistä tcp-liitynnän sisältö (ei käyttöliittymää- eli Dialogin sisältöä).
- Tutustu Kvaserin simplewrite.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogsta.
- Tutustu Kvaserin canmonitor.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogsta.
- Tutustu Qwt esimerkkeihin ja tee kolmannen esimerkin pohjalta ohjelma, joka piirtää plot-ikkunaan cosini-käyrää.
- Tee sql esimerkin avulla projektitietokanta, jossa on sarakkeet ProjektinNimi, AloitusPvm, Projektipaallikko, Budjetti.
- Ota paluuarvot talteen edellisen tehtävän sql-kyselyistä ja näytä virheet QMessageBoxilla. Käyttäjätunnus root ja salasana huhtikuu.
- Asenna tietokooneeseen MySql palvelin ja core.
- Asenna MySql Administrator, Query Browser ja Worbench
- Tee tehtävän 18. taulu MySql-tietokantaan.
- Suunnittele luokkamalli koneelle. Luokka Kone koostuu luokista Toimilaite ja Prosessi. Toimilaite koostaa luokan Liikeanturi ja VoimaAnturi. Nämä luokat taas perivät luokan Anturi. Tee luokista ensin UML-malli Dia:lla ja sitten Qt:llä.
- Muokkaa mallia siten, että teet luokan dialogi ja laitat sen jäseneksi luokan Kone. Periytä Kone luokasta QThread.
- Korjaa Dialla tekemä malli edellisen tehtävän mukaiseksi.
- Lisää anturille jäsenet double vahvistus, double offset, double tulo, double tuloSiYksikkona, double taarattuTuloSiYksikkona, double KeskiarvoistusVektori[10], i , int paikkaVektorissa, double Summa
- Tee käyttöliittymään nappi MittaaTulo ja sille Dialog luokkaan slot Mittaa. Laita myös LineEdit tai lcd, josta voit lukea mitatun arvon.
- Tee Dialog luokkaan signaali MittaaTulonArvo.
- Tee luokkaan Anturi slot void PaivitaTulo();
- Yhdistä signaali MittaaTulonArvo slotiin PaivitaTulo.
- Emitoi (lähetä) signaali MittaaTulonArvo käyttöliittymän slotissa Mittaa.
Tee luokkaan Anturi signaali LahetaMitattuArvo(double) ja ota se vastaan käyttöliittymässä.
ui
Dialog
Anturi
MittaaTulo->
->Mittaa
MittaaTulonArvo->
->PaivitaTulo
ArvonNaytto<-
<- LahetaMitattuArvo(double)
- Laita jokin arvo emitoimaasi signaaliin LahetaMitattuArvo(double) ja testaa, että arvo tulee näytölle.
- Tee käyttöliittymään Horizontal Slider ja välitä se signaali - slot mekanismilla Anturi- luokan muuttujaan tulo.
- Tee Anturi-luokkaan funktio Paivita. Kutsu tätä edellisessä tehtävässä tekemästäsi slotista.
- Laita Paivita - funktion sisällöksi tuloSiYksikkona=tulo*vahvistu+offset;
- Testaa, että vahvistettu tulo tulee näytölle.
- Tee Umbrello -ohjelmalla UML-malli tähän asti tekemästäsi softasta.
Tässä tehtävässä toteutamme asynkronisen säikeen, joka lukee anturia ja lähettää signaalilla tiedon käyttöliittymälle. Tee Kone luokkaan run-funktio ja siihen forever toistorakenne. Katso mallia säikeistetystä ohjelmasta.\
Code Block language cpp collapse true //tämä luokan esittelyyn QTime displayUpdateTimer;
Code Block collapse true forever { //Tähän anturin tiedon laskenta if (NayttoAjastin.elapsed() > Paivitysaika) { Nayttoajastin.restart(); emit LahetaAnturinTiedot(Arvo); } }
- Hae koneen arvot Sqlite tietokannasta esimerkin mukaisesti.
- Tee Qwt plot esimerkki.
- Hyödynnä esimerkkiä ja tulosta anturin arvo qwtplotissa.
- Päivitä edellisiä tehtäviä kuvaava Umbrello malli.
- Tee kone esimerkki siten, että teet kaikista luokista dialogeja. Laita luokkiin toimilaite ja anturi liukupalkit, joilla voit säätää niiden antamia arvoja. Älä käytä enää QThread luokkaa kone luokan perinnässä.
- Tee dialog perustainen ohjelma ja koosta se kahdesta alidialogista. Kokeile dialogien avausta show ja exec funktioilla, mitä huomaat? Ohjeita: sisällytä "include" alidialogit päädialogin otsikkotiedostoon, tee dialogeille muuttujat päädialogiin, tee päädialogiin nappi, jolla avaat alidialogit funktioilla exec tai show.
- Lisää edellisen tehtävän dilogeihin viestinvälitystä. Lähetä viesti päädialogista molempiin alidialogeihin. Esimerkiksi niin, että teet dialogiin napin, joka lähettää editline viestin molemmille alidialogeille.
- Lisää alidialogeihin viestinvälitys toiseen alidialogiin edellisessä tehtävässä kuvatulla tavalla.
- Lisää vielä alidialogeihin vistinvälitys päädialogiin.
- Tutustu Kvaserin simplewrite.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogista.
- Tutustu Kvaserin canmonitor.c ohjelmaan ja liitä se Qt- dialogiin siten, että voit syöttää ohjelman tiedot dialogista.
- Tee ohjaus manipulaattorille, joka nostaa laatikon pöydältä ja laittaa sen toiselle pöydälle.
- Tee edellinen tehtävä käyttäen switch-case rakennetta ja QTimer ajastinta. Kts. Qt:n wiki.
- Tee edellinen tehtävä käyttäen tilakoneessa omaa Säiettä QThread.
- Asenna koneeseesi Synapticin avulla Sliteman Sqlite tietokanta editori.
- Tee tietokanta Sliteman ohjelmalla ja lisää siihen taulu Sylinteri, jossa on kentät id, nimi, isku, vahvistus ja tulosta taulun asetukset tekstitiedostoon.
Kokeile tehdä samainen taulu seuraavalla sql-komennolla:
Code Block language SQL collapse true CREATE TABLE sylinteri ( id INTEGER PRIMARY KEY NOT NULL, nimi TEXT, isku REAL, vahvistus REAL );
Tee Sqlite tietokanta, joka sisältää taulut sensori kentillä sensor_id, vahvistus ja offset sekä kalibrointi kentillä kalibrointi_id, sensor_id, Todellinen, Mitattu ja vielä vierasavain tauluun sensori. Vähän mallia
Code Block language SQL collapse true FOREIGN KEY(sensor_id) REFERENCES sensor(sensor_id)
Täytä tauluihin kahden anturin tiedot ja testaa tiesotjen hakua sql-komennoilla, esimeriksi
Code Block language SQL collapse true SELECT * FROM kalibrointi WHERE sensor_id=1;
Tee ohjelma, joka lukee sensorien määrän sensoritaulusta ja muodostaa tarvittavan määrän sensoreita.
Code Block language cpp collapse true //luodaan sensori osoittimena Dilogi luokkaan QVector <Sensori> sensori; //luodaan vektori, joka sisältää sensoreja // esitellään dialog.h tiedostossa esimerkiksi näin Sensori *sensori; luetaan Dialogi.cpp :ssa sensorien määrä tietokannasta ja sitten luodaan new komennolla anturit sensori=new Sensori[maara];
- Tee sovellus, joka lukee sylinteritietokannasta sylinterien tiedot ja jokaiseen sylinteriin liittyy asema- ja voima-anturi ja niille kalibrointitaulu. Muista tehdä kalibrointitauluun vierasavain anturitauluun ja anturitauluun vierasavain sylinteritauluun. Näin saat yhdistettyä anturin oikealle sylinterille ja kalibrointitaulun oikealle anturille.
Tässä tehtävässä tehdään säätöpiiri. Säätöpiirin tehtävänä on säätää sylinterille menevää ohjetta siten, että haluttu asema saavutetaan mahdollisimman hyvin. Jotta tehtävä olisi mielekäs, täytyy asema-anturin eli sylinterin oloarvon ja sylinterin halutun aseman eli sylinterin asetusarvon välistä suhdetta simuloida. Toteutetaan simulaattori tässä tehtävässä mahdollisen yksinkertaisesti seuraavan ajatuksen mukaisesti: jos ohje on suurempi kuin todellinen asema, lisätään todellista asemaa kellolla (QTimer timer muuttujan timeoutilla)
Code Block language cpp collapse true if(ohjesylinterille>olo)olo++; if(ohjesylinterille<olo)olo--;
Säätöpiiri voidaan tehdä yksinkertaisesti vähennys-ja kertolaskuilla seuraavasti:
Code Block language cpp collapse true ohjesylinterille = (asetus-olo)*vahvistus;
Tehdään tehtävä aluksi ainoastaan hyödyntäen Dialog luokkaa. Eli tehdän Dialog luokkaan slider, jolla annetaan ohjearvoja ja lisäksi edistymispalkki johon laitetaan sylinterin todellinen asema. Ohjelmoi lisäksi tarvittava ajastin, jotta saat oloarvon muuttumaan edellä kuvatulla tavalla. Testaa millä vahvistuksen arvolla saat järjestelmän toimimaan (tee ohjelmaan editline ja sille validator, jolla rajataan vahvistuksen arvot välille 0...1000).
- Lisää tehtävään Qwt:n graafinen näyttö ja piirrä siihen asetus- oloarvot.
Muuta edellisen tehtävän P-säädin PI-säätimeksi.
Code Block language cpp collapse true //lisätään summaan eroarvo, muista nollata summa muodostimessa IntegraattorinSumma+=(asetus-oloarvo); //ja sitten säädin ohjearvosylinterille=(asetus-oloarvo)*P_vahvistus+ IntegraattorinSumma*I_vahvistus;
Viritä säädin Ziegler Nichols'in säännöillä.
- Lisää mittaushaaraan liukuva keskiarvo. Kts. Qt-esimerkit.
- Lisää säätimeen D-lohko.
...