TSM - Integrarea unei aplicații de navigare cu asistentul vocal Amazon Alexa

Vlad Suciu - C++ Software Developer @ Telenav

Odată cu trecerea timpului, tehnologiile disponibile evoluează, însă la fel și modul în care interacționăm cu ele. Această creștere este naturală, întrucât pentru companiile de produse software, utilitatea tehnologilor se regăsește mai ales în interacțiunea cu utilizatorul final. Domeniul interfațării om-mașină sau, pe scurt, HMI se află într-o continuă expansiune și creează multe modalități noi de interacțiune cu tehnologiile deja prezente sau care vor urma să apară. Unul dintre aceste noi moduri de interacțiune este prin asistenți vocali, care, după cum sugerează și numele, ne ajută prin prelucrarea indicațiilor noastre vocale să îndeplinim anumite sarcini pe care le poate îndeplini doar tehnologia cu care comunică aceștia. În acest articol vom arunca o privire asupra unuia dintre cei mai cunoscuți asistenți vocali, și anume, Amazon Alexa.

Parcurgând acest articol, veți afla în ce constă soluția companiei Amazon referitoare la implementarea unui asistent vocal, cum intenționează aceștia să fie utilizat de dezvoltatorii software, precum și detalii despre structura internă a kiturilor de dezvoltare software (SDK) și cum să le integrați cu o aplicație de navigare.

Amazon are mai multe kituri de dezvoltare software pentru asistenți vocali, în funcție de tipul dezvoltatorilor: kitul Alexa Voice Service (AVS), care este destinat integrării Alexa într-un dispozitiv generic și kitul Alexa Auto (AA), destinat integrării Alexa într-un dispozitiv auto.

Kitul software Alexa Voice Service

Diagrama oficială de interacțiune a kitului Alexa Voice Service

Versiunea actuală a kitului AVS este 1.18.0, oferind suport pentru dezvoltare în C++.

Urmând diagrama AVS, modulul Audio Signal Processor va captura și prelucra sunetul din microfonul sau grupul de microfoane al dispozitivului, generând un singur stream audio, care este primit de SDS. Modulul Shared Data Stream va pune streamul audio la dispoziția cititorilor, în acest caz KWD și AIP. Sarcina modulului Key Word Detection este de a monitoriza streamul și de a trimite un semnal către AIP pentru a-l citi atunci când detectează un cuvânt cheie. Sarcina modulului Audio Input Processor este de a citi streamul de la SDS atunci când primește un semnal și de a transmite datele audio către AVS-ul din cloud prin intermediul ACL.

Responsabilitățile modulului Alexa Communication Library includ gestionarea conexiunilor și a evenimentelor către și de la AVS, fiind practic un înveliș peste modulul cloud AVS bazat pe HTTP. Următorul la rând este modulul Alexa Directive Sequencer Library, care va gestiona durata de viață și ordinea evenimentelor primite de la ACL și le va transmite unui Capability Agent corespunzător. Un astfel de agent este un executant pentru o sarcină specifică sau un set de sarcini conexe. De exemplu, agentul Bluetooth este responsabil cu gestionarea conexiunilor bluetooth, în timp ce agentul Speech Synthesizer va avea grijă să efectueze acțiunea text-to-speech (TTS) și să redea semnalele audio pe dispozitiv. Nu în ultimul rând, modulul Activity Focus Manager Library este managerul intrărilor și ieșirilor dispozitivului, asigurându-se că directivele ADSL sunt executate în ordinea stabilită.

Kitul software Alexa Auto

Diagrama oficială modulară a kitului Alexa Auto

Versiunea actuală a kitului AA este 2.1, oferind suport pentru dezvoltare atât în C++ cât și în Java pentru platforma Android.

Deși nu oferă o descriere completă a kitului, diagrama informativă de mai sus prezintă informații despre modul în care este structurat. La baza kitului se află Alexa Auto Engine împreună cu întregul modul Alexa. Aceste componente se bazează pe kitul AVS descris anterior, extinzând funcționalitățile prezente pentru industria auto.

Pentru ca dezvoltatorii software să poată să pună la dispoziție kitului funcționalități auto, specifice platformei țintă, cum ar fi furnizarea locației curente, furnizarea stării rețelei de internet sau scrierea mesajelor de logging, a fost creat modulul Core. Pe lângă acesta, modulul de Code Based Login oferă o modalitate de a iniția și menține conexiunea între dispozitiv și AVS Cloud prin intermediul conectării cu un cont de utilizator Amazon.

Toate celelalte module disponibile sunt alcătuite din interfețe pe care dezvoltatorii software trebuie să le implementeze pe platforma țintă. Interfața modulului Navigation este principalul punct de interes pentru următoarele secțiuni, fiind modulul prin care aplicația de navigare a platformei va comunica cu Alexa. Modulul Phone Control este răspunzător de generarea evenimentelor de control telefonic, modulul Address Book este responsabil pentru stocarea contactelor și a locațiilor preferate de navigare, modulul Alexa Presentation Language acordă o soluție de interfațare cu componente personalizate de tipul Alexa Skills, în timp ce modulul Car Control oferă modalități prin care Alexa poate interacționa cu dispozitivele hardware specifice mașinii, cum ar fi motoarele ferestrelor, ventilatoarele, regulatoarele de temperatură etc.

Modulul de Navigare

Continuând, vom arunca o privire asupra API-ului C++ pentru acest modul special din kitul AA 2.1. Clientul este obligat să implementeze interfața Navigator Handler, care prezintă următoarele funcționalități:

virtual std::string getNavigationState() = 0;

Această funcție este apelată periodic de către Alexa Auto Engine pentru a prelua starea aplicației de navigare. De aceea este de preferat ca aceasta să returneze starea reală de navigare, deși este posibilă returnarea unui șir gol de caractere cu ​​costul dezactivării evenimentelor de întrerupere a navigării, de adăugare sau ștergere a punctelor intermediare de pe rută și solicitarea informațiilor despre ora estimată de sosire (ETA) și distanța până la sosire (DTA).

virtual void startNavigation(
const std::string& payload) = 0;

Această funcție îndrumă clientul să înceapă navigarea către destinația prezentă în șirul de caractere din parametrul de intrare.

virtual void cancelNavigation() = 0;

Această funcție informează clientul să întrerupă navigarea dacă AVS determină interogând starea de navigare că este activă.

virtual void navigateToPreviousWaypoint() = 0;

Această funcție recomandă aplicației să navigheze până la punctul intermediar sau destinația precedentă.

virtual void showPreviousWaypoints() = 0;

Această funcție direcționează aplicația de navigare să afișeze o listă cu toate destinațiile și punctele intermediare anterioare.

virtual void showAlternativeRoutes( 
  aace::navigation::Navigation
  ::AlternateRouteType alternateRouteType) = 0;

Această funcție îndrumă aplicația client să afișeze rute alternative de navigare, cum ar fi o rută mai rapidă sau o rută mai scurtă, în funcție de valoarea parametrului de intrare.

virtual void controlDisplay(  
  aace::navigation::Navigation::ControlDisplay 
  controlDisplay) = 0;

Această funcție este mai complexă, deoarece parametrul de intrare poate avea o multitudine de valori, dar se referă, în general, la controlul modului de vizualizare a hărții sau al volumului sunetelor asociate hărții. Dispune de acțiuni cum ar fi afișarea imaginii de ansamblu a traseului și lista cu direcțiile de urmat, mărirea, micșorarea și panoramarea hărții, orientarea hărții, centrarea acesteia și activarea sau dezactivarea indicațiilor sonore oferite de sistemul de ghidare al rutei.

virtual void announceManeuver(
  const std::string& payload) = 0;

Această funcție recomandă aplicației de navigare să anunțe următoarea manevră, furnizând tipul acesteia în șirului de caractere din parametrul de intrare. Tipurile acceptate sunt curbe, ieșiri, intrări, benzi și îmbinări.

virtual void announceRoadRegulation(
  aace::navigation::Navigation::RoadRegulation
  roadRegulation) = 0;

Această funcție recomandă aplicației de navigare să anunțe regulamentul rutier solicitat de pe drumul curent, furnizând tipul acestuia în parametrul de intrare. Tipurile acceptate sunt reguli de carpool sau limite de viteză.

Unele funcții prezintă un șir de caractere în parametri de intrare numit payload, care este într-un format JSON predefinit de Alexa Auto Engine. Așa cum sugerează exemplele de implementări ale aplicației client din kit, o practică bună o reprezintă folosirea unui translator JSON bazat pe șabloane (template-uri) pentru a evita pe cât posibil overheadul la runtime asociat cu interpretarea payloadului.

Integrarea cu Qt QML

Pentru a explora cazul integrării kitului Alexa Auto într-o aplicație de navigare, vom folosi frameworkul Qt, care este utilizat pe scară largă în aplicațiile embedded, și presupunând că HMI-ul aplicației este scris în Qt Modeling Language (QML).

Întrucât frameworkul Qt oferă o soluție avantajoasă în ceea ce privește decuplarea dependențelor binare, permițând dezvoltatorilor să creeze pluginuri QML personalizate din cod C++, tot ce trebuie să facem este să înfășurăm funcțiile C++ ale modulului de navigare într-un astfel de plugin:

class AlexaWrapper : public QObject,
  public aace::engine::navigation
     ::NavigationHandlerInterface
{
  Q_OBJECT

public:
  static QObject* create(QQmlEngine* engine, 
    QJSEngine* scriptengine)
    {
      … // return singleton instance
    }

    AlexaWrapper()
    {

 …  // register the wrapper as a platform interface 
    // in the Alexa engine
    } 

signals:
    void cancelNavigationRequested();

    … // the rest of the associate signals

private:
    void cancelNavigation() override
    {
        emit cancelNavigationRequested();
    }

    … // the rest of the navigation interface 
      // definitions
};

class QAlexaVoiceAssistantPlugin : 
  public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID 
      QAlexaVoiceAssistantPlugin_IID)

public:
    void registerTypes(const char *uri) override
    {
        qmlRegisterSingletonType
        (uri, 1, 0, „AlexaVoiceAssistant”
         , AlexaWrapper::create);
    }
};

După compilarea codului de mai sus într-un shared object numit "libalexaVoiceAssistantPlugin.so" mai este necesar doar crearea fișierului qmldir pentru ca interpretorul QML să încarce pluginul Alexa Wrapper:

module AlexaVoiceAssistant
plugin alexaVoiceAssistantPlugin

Nu în ultimul rând, vom conecta obiectul de tip singleton Alexa Voice Assistant la codul HMI al aplicației din fișierele QML:

import AlexaVoiceAssistant 1.0

… // other HMI imports and code

Connections {
    target: AlexaVoiceAssistant

    onCancelNavigationRequested: {
     … // call routine to stop the navigation
       // if running
    }

    … // rest of the associate signals 
      // from AlexaWrapper
}

În concluzie, sperăm că acest articol a trezit atât interesul cititorilor cu privire la modul în care este structurat un astfel de asistent vocal, precum Amazon Alexa Auto SDK, cât și curiozitatea celor preocupați de maniera în care aceste soluții software ar putea fi implementate în stratul HMI al unei aplicații de navigare embedded.