Robik
{{{kuvateksti}}}
| }}Robik
{{#if:Robik | | }} {{#if: | | }}Tyyppi: | Laite |
Tekijät: | jari |
Aloitettu: | 2014, valmistui 2018 |
Tila: | Valmis |
GitHub: | [Robik] |
URL: | [{{{url}}}] |
Rubikin kuution ratkaisija romusta
Video: https://www.youtube.com/watch?v=gjVkjhh7wAA
Taustaa
Rubikin kuution ratkaisija on ollut “Tee tällainen joskus”-listallani jo vuosikaudet. Koska en osaa ratkaista kuutiota, pitää saada kone, joka ratkaisee. Näitähän on netti väärällään mitä erilaisimpia konstruktioita, mutta kokonaan romusta tehtyä en ole nähnyt, joten ainakin tämän verran on uutta tulokulmaa.
Alusta saakka ajatus oli käyttää kirjoittimen mekaniikkaa kuution vaakasuoran kaatoliikkeen toteuttamiseen. Alkujaan ajattelin käyttää koko laitteeseen vain kaksi moottoria, yksi kaatamiseen ja yksi pyörittämiseen/vääntöjen tekemiseen. Tällöin värien tunnistimetkin olisivat liikkuneet vaakaliikkeen mukana. Luovuin kuitenkin tuosta ajatuksesta ja päädyin Tilted Twisteristä tuttuun kolmimoottoriseen perusrakenteeseen, joka on paljon käytetty rakenne.
Alkuperäinen ajatus ei ollut tehdä tästä 100% kierrätysprojektia. Vaikka perusmekaniikka tuleekin edesmenneestä kirjoittimesta, ainakin CPU-kortiksi arvelin tarvitsevani kaupasta ostetun, joka jaksaa vääntää sekä mekaniikan ohjauksen että kuution ratkaisualgoritmin. Mutta siinä vaiheessa kun Harri Larjoston taideprojektin jälkeenjääneet romut päätyivät varastoihini, älysin projektissa käytetyn robotti-imurin keskusyksikkökortin käyttökelpoisuuden, ja päätin muuttaa projektin fokuksen kierrätysprojektiksi. Projektin romuaste on ehkä 99%, koska ruuvit, kierretangot ja kutistesukka ovat uusia. Varsinkin viimemainitun kierrättäminen on aivan erityisen hankalaa.
Mekaniikka
Laitteen mekaniikka tulee kahdesta mustesuihkukirjoittimesta (Xerox Docuprint ja HP OfficeJet) sekä robottipölynimurista (Yujin iClebo). Lisäksi satunnaista puu-, metalli- ja muovijätettä.
Vaakaliikkeen tehtävä on pyöräyttää kuutiota vaaka-akselinsa ympäri neljänneskierros. Tämän se tekee kaatamalla kuution kyljelleen ja vetämällä sen paluuliikkeen aikana takaisin kääntöpöydälle. Perustana on Xeroxin kirjoitinpään mekanismi, jossa askelmoottori liikuttaa kirjoitinpään kelkkaa hammashihnan välityksellä. Xerox on sen verran vanha kirjoitin, että askelmoottori on vielä kunnollisen kokoinen, eli se jaksaa vääntääkin kohtuullisesti. Kaadosta tulee väkisinkin hidasliikkeinen tällä rakenteella, mutta tällä robotilla ei pyritäkään speed cube -kisan kärkisijoille. Nopeutta joutui hidastamaan vielä lisää, koska askelmoottoria ajetaan open loop -tyyppisesti, eli nopeus pitää olla niin pieni, että askelia ei hukata edes silloin, kun kaatopään palkit törmäävät kuutioon, koska samalla hukataan paikka. Siitäkin huolimatta vaakaliikkeen putoaminen synkasta on usein toistuva syy kuution ratkaisemisen epäonnistumiseen.
Kuution kaadon periaate on käsitykseni mukaan uniikki, en ole nähnyt juuri tällä periaatteella tehtyä kaatoa missään. Sitä harjoittelinkin pitkään, aluksi Lego-rakennelmalla ja myöhemmin pahvimalleilla, ks. oheiset kuvat. Kaatopään sivulevyt ovat mustaksi eloksoitua alumiinia, tehty labilta löytyneistä tuntemattoman laitteen kotelon osista. Nämä ovat kierretangoilla kiinni kirjoitinpään kelkassa. Liikkuva akseli on kirjoittimen paperinsyöttökoneiston akseli, jossa oli oikein sopivat kumirullat valmiina.
Kääntöpöytä hoitaa kahta tehtävää: koko kuution pyörittäminen pystyakselinsa ympäri tai kuution alimman tahkon vääntäminen, kun kaatopää on ajettu kuution kohdalle siten, että se estää kahden ylemmän kerroksen pyörimisen mukana.
Kääntöpöytä oli aluksi tarkoitus tehdä robottipölynimurin pyörä/moottori-kokonaisuudesta. Siinä on valmiiksi välitetty DC-moottori, jossa on hall-antureilla toteutettu kvadratuurianturi moottorin akselilla. Vaihteistossa oli kuitenkin aivan liikaa klappia tähän tarkoitukseen, joten lopullisessa konstruktiossa on vain robotin pyörä ja sen laakeri, moottoriksi on istutettu OfficeJetin skannerin arkinsyöttölaitteen moottori vaihteistoineen. Tässäkin on optinen kvadratuurianturi moottorin akselilla, ja siedettävämpi määrä klappia. Absoluuttiasento löydetään imurin moottorista otetulla hall-anturilla ja pyörään liimatulla magneetilla. Koko rakennelma on kiinnitetty ruuvien varaan siten, että sen paikkaa voi hienosäätää suhteessa kaatopäähän.
Värintunnistinpään siirtomekanismi on Xeroxin kirjoitinpään puhdistuskoneisto, jossa oli askelmoottori ja sopiva ratasvälitys sekä indeksiopto absoluuttiasennon löytämistä varten. Tähän on lisätty riittävän pitkä varsi, jonka päässä varsinainen tunnistinpää siirtyilee paikasta toiseen. Tässäkin vaihteistossa on klappia vähintäänkin riittävästi, etenkin pitkän varren päässä, mutta tunnistinpään liikkeet ovat varsin yksinkertaisia ja siksi klappi on melko helposti hallittavissa.
Elektroniikka
Keskeisin osa elektroniikasta on CPU-kortti, joka on robotti-imurin ohjainkortti. Siinä on kontrollerina STM32F101, jossa on 64 KB flash ja 10 KB RAM, max kello 36 MHz. Ohjelmointipinnit on tuotu valmiiksi liittimelle, joten ohjelmointi ja debuggaus onnistuu suoraan kiinalaisten halpis-ST/LINK-kloonilla. Oikein hakkerointiystävällinen konstruktio siis. Lisäksi I/O:ta on runsaasti: H-sillat ja kavdratuurianturien otot imurin kahdelle ajomoottorille, muutama isompitehoinen FET imurin apumoottorien käynnistämiseen, iso joukko ULN2004-puskuroituja lähtöjä kaikenlaisten anturien ja näytön hallintaan ym. OfficeJetin arkinsyöttölaitteen moottorin ohjaus ja kvadratuurianturin lukeminen onnistui suoraan kortilla olevilla varusteilla.
Imurin kortti on tehty toimimaan yhdellä akusta saatavalla n. 16V jännitteellä, ja se sisältää hakkurit, jotka tekevät muut tarvittavat jännitteet: 3.3V, 5V ja 12V. Robikissa korttia syötetään tavallisella seinään työnnettävästä 12V pikkupowerista modifioidulla sähkölähteellä, jolla se näkyy toimivan ihan hyvin.
Molemmat askelmoottorit (vaakaliike ja värintunnistinpään liike) ovat peräisin Xeroxin kirjoittimesta, joten sieltä on otettu myös niiden ohjainkortti ja poweri. Tällöin jännittteet, ohjainpiirien virtakestot ja muut osuvat varmasti kohdalleen ilman ihmettelyjä. Xeroxin kontrollerilta tulevat ohjaukset on katkaistu ja siirretty tulemaan imurin CPU-kortilta.
Alkuperäinen toive oli saada myös kuution ratkaisualgoritmi mahtumaan imurin STM32:een, mutta tämä osoittautui aika lailla mahdottomaksi, joten tarvittiin toinen kontrolleri tätä varten. Tähän löytyi Aidonin sähkömittarin hajonnut tietoliikennemoduuli, jossa on hiukan isompi ARM: LPC2366, jossa on 256 kB flash ja n. 50 kB RAM, max kellotaajuus 72 MHz. Tämä ei ole Cortex-sarjaa vaan vanhempi ARM7TDMI. Kortilta oli hajonnut hakkuri, joka tekee 230V:sta kortille käyttösähköt, mutta syöttämällä sinne 3.3V suoraan Xeroxin powerista se toimii ihan ongelmitta. NXP:n kontrollereissa on aina sarjaportti-bootloader, joten kortin ohjelmointi onnistui suoraan FlashMagicilla sähkömittarin paikallisloggausta varten tarkoitetun RS232-portin kautta. Tällä järjestelyllä ei voi debugata ohjelmaa, mutta se ei nyt tässä haitannut.
Näytön pelastin talteen Hacklabin romukasasta jo vuosia sitten. Ei tietoa, mikä sen käyttötarkoitus on ollut, mutta form factor vaikuttaa siltä, että se on tarkoitettu asennettavaksi PC:n 5,25 tuuman levyasemapaikkaan, jolloin näyttö jää esille etuseinään. Joka tapauksessa siinä on 2*16 merkkinen alfanumeerinen VFD-näyttö ja sitä ohjaava kontrolleri. Lisäksi siinä on pari painiketta. Robik-käyttöä varten irrotin näytön ohjaavasta kontrollerista, siinä on ihan standardi HD44780-rajapinta, jota STM32 ohjaa suoraan.
Värintunnistinpää on yksinkertainen: siinä on RGB-ledi ja valotransistori. Ledin kutakin osaväriä ohjataan PWM:llä ja valotransistori luetaan A/D-muuntimella.
Ohjelmisto
Robik-käytössä imurin STM32:een on tehty uusi ohjelma, joka hoitaa kaiken mekaniikan ja näytön ohjaamisen, ei kuitenkaan varsinaista kuution ratkaisua. Ohjelma sinänsä on aika perusmekaniikan ohjausta: luetaan antureita, askelletaan askelmoottoreita kiihdytys/hidastusramppeineen, pyöritetään kääntöpöytää PWM:llä, seurataan pyörimistä kvadratuurianturilla (tässä on Kremmenin neuvoma kahden sisäkkäisen PID-säädön periaate, joka toimii hyvin, kiitokset), keskustellaan sarjaportista ratkaisijakortin kanssa ja välillä kirjoitellaan näytöllekin yhtä ja toista. Projekti oli hyvä STM32-harjoitus: suunnilleen kaikki F101:n ominaisuudet on käytössä. Käyttöjärjestelmänä on FreeRTOS ja ohjelmointiympäristönä CooCox.
FreeRTOS osoittautui yllättävän muistisyöpöksi. Kun olin suunitellut sinne toistakymmentä taskia ja niiden välille jonoja, semaforeja ja muuta sälää, totesin, että 10KB RAM ei riitä. Piti suunnitella taskirakenne uusiksi, nyt niitä on vajaa 10 ja muisti riittää, mutta ei siellä juuri ylimääräistäkään ole.
STM32:n yhdessä sarjaportissa on komentorivikäyttöliittymä, jolla mekaniikkaa voi testata ja säätää komentamalla sitä tekemään yhden asian kerrallaan. Ilman tällaista kokonaisuuden toimimaan saaminen olisi jokseenkin mahdotonta.
Imurikortti hoitaa myös värien tunnistuksen. Tässä testailin ilmeistä algoritmia, eli väläytetään ledin kutakin osaväriä, mitataan valotransistorin antama arvo kullekin, ja haetaan väri taulukosta. Ei toiminut ollenkaan. Kuutio oli käytetty (koska kierrätysprojekti) ja osa pikkuneliöistä on aika naarmuuntuneita. Silmälle saman väriset neliöt antavat hyvin erilaisia mittaustuloksia. Erinäisten kokeilujen jälkeen päädyin sitten paremmin toimivaan algoritmiin: ajetaan PWM:ien avulla hyvin valittu väri lediin ja mitataan valotransistorin arvo, josta voidaan päätellä, kumpaan kolmen värin ryhmään mitattava väri kuuluu. Tämä toistetaan toisella sopivasti valitulla ledin värillä, jolloin saadaan mahdollisuudet supistettua yhteen tai kahteen. Näin jatkaen väri saadaan selville enintään kolmella mittauksella. Tämä algoritmi toimii huomattavasti luotettavammin, kunhan lediin ajettavat värit on valittu viisaasti.
Kaiken tämän jälkeenkin värintunnistusvirheitä tuli sietämättömän paljon, ja labilla demotilanteissa ratkaisuyritys päättyi tällaiseen virheeseen aivan liian usein. Jouduin sitten ottamaan lusikan kauniiseen käteen ja toteamaan, että kierrätysprojekti tai ei, siihen on saatava uusi ja naarmuuntumaton kuutio. Kunhan värintunnistin oli kalibroitu uudelleen uuden kuution värisävyille, tunnistuksen onnistuvuus parani todella paljon värineliöiden tasalaatuisuuden ansiosta. Nykyisellään värintunnistusvirheet ovat kohtalaisen harvinaisia.
Sähkömittarin tietoliikennemoduuli ajaa pelkästään Rubikin kuution ratkaisualgoritmia. Siinä ei ole mitään käyttöjärjestelmää, koska ohjelma on rakenteellisesti yksinkertainen, vaikkakaan ei algoritmisesti. Tässä ohjelmointiympäristönä on LPCXpresso, ja flashays suoraan sarjaportista FlashMagicilla.
Imurikortin ja sähkömittarikortin välillä on sarjaportti ja siinä hyvin yksinkertainen protokolla. Imurikortti lähettää tunnistamansa värit merkkijonona mittarikortille, joka ajaa ratkaisualgoritmin ja lähettää ratkaisuun tarvittavat väännöt takaisin merkkijonona. Imurikortti ohjaa sitten mekaniikkaa siten, että kuutiota väännellään saatujen ohjeiden mukaisesti. Helppoa kuin heinänteko.
Mittarikortin puolella pyritään myös korjaamaan värintunnistuksen tekemiä virheitä ennen ratkaisualgoritmin ajamista. Koska kuution väreissä on paljon sisäistä redundanssia, on aika helppo päätellä, onko värit tunnistettu oikein, eli voiko värit olla tuollaisessa järjestyksessä. Netistä löytyneen tarkistusalgoritmin lisäämisen jälkeen pystytään korjaamaan (päättelemään, miten värit ovat todellisuudesssa olleet) lähes kaikki yhden värin virheet ja joitakin sopivasti osuneita kahden tai kolmen värin virheitäkin.
Github-linkki source-koodeihin löytyy sivun ylänurkan laatikosta.
Ratkaisualgoritmi
Sopivan kuution ratkaisualgoritmin löytäminen oli operaatio sinänsä. Nykyiset algoritmit ovat hyvinkin kehittyneitä, mutta piti löytää algoritmi, joka mahtuu käytettävissä olevien kontrollereiden muisteihin. Tehokkaat algoritmit haukkaavat megatavuja RAMmia, mikä ei ole PC:ssä ongelma, mutta tässä käytetyissä kontrollereissa on.
Löysin sitten webbisivun http://tomas.rokicki.com/cubecontest/winners.html, jossa oli pidetty kilpailu mahdollisimman pienikokoisesta Rubikin kuution algoritmista. Sieltä löytyi potentiaalisia ehdokkaita useampiakin. Testailin Charles Tsain esittämää algoritmia ensin. Se oli niin yksinkertainen, että se olisi saattanut mahtua jopa STM32:n puolelle, mutta se tuotti aivan liian paljon siirtoja, keskimäärin yli 100. Ottaen huomioon mekaniikan hitauden ja epäluotettavuuden, ratkaisussa olisi vain harvoin päästy loppuun saakka, ennen kuin mekaniikka tekee virheen. Ja sen kerran kun päästään, katsojat ovat ehtineet jo nukahtaa.
Sitten kun olin tunnustanut itselleni, että tarvitsen erillisen kontrollerin ajamaan algoritmia ja löytänyt sähkömittarin kortin tähän, totesin että saman kilpailun osallistujista Jaap Scherphuisin algoritmi saattaisi mahtua LPC2366:een. Ilman muutoksia ei toiminut tuokaan. Koska kilpailun tavoite oli ollut löytää source-koodiltaan mahdollisimman pienikokoinen algoritmi, tämä algoritmi laski ensin isoja vakiotaulukoita, jotka tarvitaan varsinaiseen ratkaisuun. Taulukot ovat isompia kuin ne tuottava algoritmi, joten pienuuskisassa järkevää. Osoittautui kuitenkin, että taulukoiden laskenta 72MHz LPC2366:ssa kestää paljon yli 10 minuuttia. Ei hyvä.
Päädyin muuttamaan ohjelmaa siten, että laskin vakiotaulukot PC:ssä valmiiksi ja otin ne vakioina mukaan koodiin; kontrollerissa on kuitenkin flashia runsaasti. Tämän muutoksen jälkeen algoritmi toimii ihan riittävän nopeasti tähän käyttöön. Tämä on sikäli ihanteellinen algoritmi, että se tuottaa muutaman ensimmäisen siirron hyvin nopeasti (luokkaa sekunnissa), jolloin mekaniikka voi ruveta suorittamaan niitä heti. Useimmiten algoritmi ehtii laskea tukun uusia siirtoja ennen kuin mekaniikka on ehtinyt suorittaa siihen mennessä lasketut, joten siirtoja suoritetaan keskeytymättä. Ratkaisuun kuluva aika vaihtelee kuitenkin paljon, ja silloin tällöin tulee tilanne, jossa mekaniikka pysähtyy odottamaan lisää siirtoja algoritmilta. Tämä aiheuttaa aina hölmistymisen “mitäs nyt tapahtui?”. Pahimmillaan olen nähnyt jopa parin minuutin pysähdyksiä, kun algoritmi jauhaa. Silti ratkaisu tulee sieltä ja suoritetaan loppuun saakka.
Algoritmi perustuu Thistlethwaiten algoritmiin, ja sen tekemästä pyörittelystä en ymmärrä paljoakaan, mutta koodi on perus-C:tä eikä käytä mitään kummallisia kirjastoja, joten se kääntyi ongelmitta ARMille. Algoritmi tuottaa yleensä hiukan alle tai yli 30 siirtoa, yksinkertaiset 3 tai 4 siirron ratkaisut se löytää suoraan.
Ratkaisu kestää yleensä noin 5 min, josta 1 min värien tunnistamiseen ja 4 min siirtojen suorittamiseen (30 siirtoa). Videossa on asioiden nopeuttamiseksi valittu sekoitus, joka tuottaa vain 14 siirtoa.