Psyclone: raddstýrður bíll

Markmið: Að tengja saman nokkur forrit með Psyclone og búa þannig til raddstýrðan bílaleik
Forkröfur eru: grunnþekking á Sphinx-4, Psyclone, Java og hlutbundinni forritun,
Tól sem þarf: Java SDK 1.4.2, OpenAIR, Psyclone, JPCT og einhvert þróunarumhverfi t.d. Eclipse


Jæja þá er loksins komið að því að við gerum eitthvað annað en bara að kynna dót sem aðrir hafa búið til. Að þessu sinni ætlum við að búa til eitthvað "nytsamlegt" þ.e. (eins og kemur fram hér að ofan) að búa til raddstýringu ofan á bílaleik. Ef þið hafið lesið þær leiðbeiningar sem eru gefnar á þessari síðu þá ættuð þið að hafa rekist á leiðbeiningar um JPCT þar sem farið er í hvernig á að skrifa viðmót ofan á bílaleik sem tekur inn texta frá lyklaborði. Ástæðan fyrir því að JPCT leiðbeiningarnar eru nefndar hér er sú að við ætlum að taka það sem við bjuggum til þar og breyta því. Breytingin felst aðallega í því að í stað þess að taka inn skipanir frá lyklaborði þá ætlum við með hjálp Psyclone og Sphinx-4 að taka inn skipanir frá míkrófón.

Þetta kann að hljóma rosalega flókið en er í raun fáranlega einfalt þar sem að í Psyclone og Sphinx-4 er búið að fela fyrir okkur allt sem talist getur flókið.

Við ætlum að nota hlut sem Java býður upp á sem flestir hafa ábyggilega ekki notað mikið þ.e. þræði. Ekki verður farið nákvæmlega út í það hvernig þræðir virka en nauðsynlegt er þó að skilja til hvers þeir eru áður en lengra er haldið. Þræðir eru í stuttu máli aðferð til að keyra mörg ferli "samtímis". Ástæðan fyrir því að samtímis er haft innan gæsalappa hér er sú að í tölvu með aðeins einn örgjörva þá er ekkert raunverulega keyrt á nákvæmlega sama augnablikinu heldur skiptast þræðir og ferli í tölvunni á um að nota örgjörvann. Þau forrit sem notast við þræði í Java, erfa frá klasa sem nefnist Thread og útfæra fall sem nefnist run. Fyrir þá sem vilja lesa sig til um þræði áður en lengra er haldið geta skoðað upplýsingar um það hér eða hér.

Áður en lengra er haldið þá er best að ræsa Psyclone. Við förum ekki nánar í Psyclone hér og fyrir þá sem ekki þekkja Psyclone og vita þ.a.l. ekki hvað hann gerir, þá er hægt að kynna sér málið hér.

Næst skulum við skoða hvað það er í raun sem við þurfum að gera.

  • Forrit sem greinir skipanir frá míkrófón og sendir þær áfram til Psyclone
  • Forrit sem gerist áskrifandi að skipanunum hjá Psyclone og kemur þeim áfram til bílaleiks

Þetta virðist nú ekkert vera neitt rosalega mikið mál? Enda er þetta eins og áður sagði alveg fáránlega einfalt og hver sem er, sem hefur smá tíma aflögu og nennir að fikta sig áfram, er fær um að gera þetta á tiltölulega stuttum tíma.

Við þurfum að ganga frá einu smáatriði áður en við höldum lengra áfram og það er að búa til málfræðiskjal fyrir Sphinx-4. Farið hefur verið áður í það hvernig slíkt skjal er uppbyggt þannig að við sýnum eingöngu tilbúið skjal hér.

#JSGF V1.0;

grammar command;

public <tell> = ( left | right | forward | back | stop );

Þessi málfræði byggist á 5 skipunum þ.e. left, right, forward, back og stop.

Forritið sem tekur inn hljóð frá míkrófón er sáraeinfalt það eina sem það gerir er að ræsa Sphinx-4 talgreininn og senda það sem Sphinx-4 greinir áfram til Psyclone.

public void run()
{
    while ( true )
    {
        System.out.println( "Now listening ... " );
        String command = null;

        try
        {
            command = listen();
        }
        catch ( Exception e )
        {
            System.err.println( "Error: " + e.getMessage() );
            e.printStackTrace();
        }

        if ( command != null )
        {
            m_poster.post( "WB1", "My.Speech.Command", command );
        }
    }
}

public String listen() throws Exception
{
    if ( !m_microphone.isRecording() )
    {
        throw new Exception( "Microphone is not recording!" );
    }

    String resultText = null;
    m_microphone.clear();
    Result result = m_recognizer.recognize();

    if ( result != null )
    {
        resultText = result.getBestFinalResultNoFiller();
    }
    return resultText;
}

Hér höfum við tvö föll annað sem fer í endalausa lykkju og hlustar eftir skilaboðum og ef um er að ræða skilabð þá póstum við þeim á "krítartöflu" (e. whiteboard) WB1. Hitt fallið greinir skipanir frá míkrófón með hjálp Sphinx-4 talgreinisins og skilar þeim sem streng til baka. Taka skal fram að þetta er ekki allt forritið og verður kóðinn fyrir því gefinn síðar.

Nú erum við búin með annað forritið sem við ætluðum að gera og þá er bara að vinda sér í hitt þ.e. forritið sem sér um að gerast áskrifandi að Psyclone og skipa bílaleiknum fyrir. Þetta forrit sér líka um að ræsa bílaleikinn.

public Message acceptMessage( Message message )
{
    Time now = new Time();
    Message msg = MessageProcessor.getTriggerMessage( message );
    ObjectCollection msgs = MessageProcessor.getRetrievedMessages( message );
    RawXML phasespec = MessageProcessor.getPhaseSpec( message );

    if ( ( phasespec == null ) || ( msgs == null ) || ( msg == null ) )
    {
        System.out.println( "JavaReader: received faulty wakeup message..." );
    }
    else
    {
        System.out.println( now.printTime() +
                ": JavaReader: received wakeup message from " + msg.from );

        if( msg.content.toLowerCase().equals( "left" ) )
        {
            m_test.setLeft( !m_test.isLeft() );
        }
        else if( msg.content.toLowerCase().equals( "right" ) )
        {
            m_test.setRight( !m_test.isRight() );
        }
        else if( msg.content.toLowerCase().equals( "forward" ) )
        {
            m_test.setForward( !m_test.isForward() );
        }
        else if( msg.content.toLowerCase().equals( "back" ) )
        {
            m_test.setBack( !m_test.isBack() );
        }
        else if( msg.content.toLowerCase().equals( "stop" ) )
        {
            m_test.setForward( false );
            m_test.setBack( false );
            m_test.setLeft( false );
            m_test.setRight( false );
        }
    }
    return null;
}

Eins og í öllum forritum sem nota JavaAIRPlug þá þurfum við að yfirskrifa fallið acceptMessage. Við notum föllin sem eru innbyggð í bílaforritið til að stýra bílnum t.d. setForward() segir bílnum að fara áfram ef inntakið er true en segir bílnum að hætta að fara áfram ef inntakið er false.

Þá höfum við lokið við að gera raddstýrðan bíl. Bíddu er þetta allt og sumt? Já, hversu ótrúlegt sem það kann að virðast þá er ekki meira mál en þetta að búa til raddstýrðan bíl með hjálp jPCT, Sphinx-4 og Psyclone. Eflaust hafa mörg ykkar sem hafa lesið í gegnum þetta ímyndað ykkur fullt af forritum sem hægt er að útfæra á samskonar hátt og gert var hér með raddstýringu og bílaleik. Möguleikarnir eru eins og áður hefur verið sagt endalausir og í raun það eina sem takmarkar það hvað hægt er að gera er ímyndunaraflið og því miður reiknigeta tölvunnar :).

Fyrir þau ykkar sem viljið nálgast kóðann af þessu verkefni þá er hægt að sækja hann hér.

 

CADIA
cadia@ru.is  |  Ofanleiti 2, IS -103 Reykjavík
Tel: +354 510 6427  |  Fax: +354 510 6201