RoboCam · ProgHouse-artiklar

Version 1.3.1 · översatt artikel

Bygg förstapersonsstyrning för en Arduino-robot

Översatt från den ryska originalartikeln av Alexej (ПрогХаус), publicerad 6 oktober 2017.

Skärmbilderna är från originalartikeln och har retuscherats så att gränssnittstexten är på svenska. De orörda originalen visar det ryska gränssnittet.

Den senaste versionen av RoboCam kan styra inte bara EV3-robotar utan även robotar byggda på plattformar som Arduino, Raspberry Pi och liknande, där man kan arbeta direkt med data som tas emot och skickas via Bluetooth. Nu kan du hantera RoboCams kommandon precis som du vill.

Bygg förstapersonsstyrning för en Arduino-robot

Den här artikeln beskriver de nya funktionerna i RoboCam version 1.3.1. Alla artiklar om RoboCam finns här. Du kan installera RoboCam från Google Play, eller ladda ner APK-filen och installera den manuellt: den vanliga versionen av RoboCam eller versionen av RoboCam som använder RenderScript (för vissa äldre telefoner); båda är utgåva 1.4.5. Det finns också en APKPure-spegling.

Allt som gjordes för EV3 i de tidigare versionerna är oförändrat. Den nya versionen lägger bara till en drivrutin och inställningar för att arbeta med robotar som kan ta emot kommandon direkt från RoboCam via Bluetooth, bearbeta dem och skicka svar. Sådana robotar kan byggas på olika plattformar (Arduino, Raspberry Pi, PC) och köra olika firmware och operativsystem (standardfirmware för Arduino, Windows, Linux, Android med flera). Programmet som pratar med RoboCam kan också skrivas i olika programmeringsspråk.

Eftersom robotens firmware eller operativsystem kan variera beskriver jag nedan bara protokollet för kommunikation med RoboCam och de nya inställningarna, och ger ett exempelprogram för att styra en hjulrobot med styrbar telefonhållare på Arduino-plattformen.

Robotarna som beskrivs ovan kallas i den här artikeln och i inställningarna icke-standardrobotar.

Här är en video där en Arduino-robot styrs i förstaperson med RoboCam. Längre ner i artikeln beskrivs hur och med vad man bygger en sådan robot.

Så kommunicerar RoboCam och roboten

Det första som behövs för att RoboCam och roboten ska börja kommunicera är att i programvaran ansluta till Bluetooth-modulen och vänta tills data börjar komma från den. Det görs olika på alla system och kan inte beskrivas i en enda artikel. Därför ger jag exempel bara för Arduino-plattformen, och specifikt för konfigurationen Arduino Uno + Bluetooth-modul HC-06. Jag utgår från att HC-06 har standardinställningar (9600 baud) och är ansluten på standardsättet (modulens RX-stift till Arduino Unos TX-stift, och modulens TX-stift till Arduino Unos RX-stift). Vid standardanslutning går allt Bluetooth-arbete på Arduino via serieporten med 9600. I kod ser initieringen av porten ut så här:

void setup()
{
    Serial.begin(9600);
}

Som du ser är det enkelt. Därefter kan du läsa och skicka data via Bluetooth. På Arduino görs det med metoderna i klassen Serial, som read(), write(), available() med flera.

När RoboCam-appen ansluter till ditt program tar den direkt initiativet: RoboCam skickar meddelanden med kommandon, och ditt program bearbetar kommandona och skickar tillbaka meddelanden med svar. Alla kommandon och svar går i sekvens: först kommer ett kommandomeddelande från RoboCam, sedan måste ett svarsmeddelande gå tillbaka, varefter RoboCam skickar nästa kommando, som återigen måste besvaras, och så vidare.

Ditt program bör svara på varje kommandomeddelande så snabbt det kan. Ju längre ditt program tar på sig att svara, desto sämre blir i slutändan robotens respons på användarens handlingar.

Ett svar på varje meddelande förväntas inom en sekund. RoboCam behandlar ett svar som fördröjs mer än en sekund som ett fel.

Varje meddelande är en viss uppsättning byte. De första två byten innehåller ett tal som anger meddelandets storlek i byte. Dessa två första byte räknas inte som en del av meddelandet. Om de första två byten alltså anger 5 följer ytterligare 5 byte, och det är själva meddelandet. Ett meddelande läses därför så här: först läser du de första 2 byten och omvandlar dem till ett teckenlöst tvåbytes heltal, sedan läser du lika många byte till som talet anger. Här är ett exempel på hur man läser meddelandets storlek på en Arduino:

//I variabeln messageSize lagrar vi meddelandets storlek.
unsigned int messageSize = 0;
//Kontrollera om två byte kan läsas från serieporten.
if (Serial.available() > 1)
    //Läs in meddelandets storlek i variabeln messageSize.
    messageSize = Serial.read() + (Serial.read() << 8);

Därefter kan du läsa hela meddelandet till en matris, till exempel så här:

//Variabeln readMessageBytes används som räknare för lästa byte.
unsigned int readMessageBytes = 0;
//Kontrollera om alla byte i meddelandet har lästs och om det finns data i serieporten.
while (readMessageBytes < messageSize &amp;&amp; Serial.available() > 0)
{
    //Läs en byte.
    message[readMessageBytes] = Serial.read();
    //Öka räknaren för lästa byte med 1.
    readMessageBytes++;
}

I exemplet ovan lämnas slingan om det inte finns någon data att läsa i serieporten. Vi väntar alltså inte på att meddelandet ska läsas helt. Med det tillvägagångssättet läser vi meddelandet allteftersom data kommer och gör samtidigt något annat i den oändliga slingan i vår Arduino-skiss, i funktionen loop().

När meddelandet har lästs (i exemplet ovan sker det när värdet på readMessageBytes blir lika med värdet på messageSize) kan det tolkas, och efter tolkning och sändning av svaret läser du nästa meddelande, och så vidare.

Ett svarsmeddelande skickas så här: först bygger du meddelandet, till exempel genom att lägga det i en bytematris, sedan räknar du ut storleken på det resulterande meddelandet och skickar den som de första två byten, följt av själva meddelandet, det vill säga den förberedda bytematrisen. Ett exempel på att skicka ett svarsmeddelande på Arduino ser ut så här:

//Säg att variabeln replySize innehåller svarsmeddelandets storlek.
unsigned int replySize = 0;
//Och matrisen reply innehåller svarets byte.
byte reply[20]; 
//Bygg svaret och lägg det i matrisen reply.
//Räkna samtidigt ut svarets storlek i byte och lägg den i variabeln replySize.
...
//Skicka först meddelandets storlek.
Serial.write(replySize &amp; 0xFF);
Serial.write((replySize >> 8) &amp; 0xFF);
//Skicka sedan det förberedda meddelandet.
Serial.write(reply, replySize);

Meddelandenas innehåll

När ditt program har läst ett meddelande till en matris kan meddelandet läsas. Meddelandets första byte innehåller kommandokoden. Alla övriga byte beror på kommandot. Kommandona är:

För enkelhets skull är det bäst att direkt deklarera konstanter för kommandona i ditt program (längre fram i artikeln använder jag namnen på konstanterna för bekvämlighets skull):

const byte CMD_START = 0; 
const byte CMD_CALLSIGN = 1;
const byte CMD_CTRL = 2;
const byte CMD_TEST = 3;
const byte CMD_STOP = 255;

Roboten måste svara på varje kommando den tar emot. Som skrivet ovan är svaret också ett meddelande. Meddelandets första byte (naturligtvis efter de två byten med meddelandets storlek) är resultatkoden. Om fler byte följer, och vad de innehåller, beror på kommandot som besvaras.

Resultatbyten kan bara ha två värden:

Nu tittar vi närmare på kommandona och svaren på dem.

Kommandot «Start» (CMD_START)

Med det här kommandot börjar samtalet mellan roboten och RoboCam (det sker efter att du tryckt på den mittersta lila knappen i RoboCam och valt en robot i listan). Som svar på kommandot måste roboten returnera ett korrekt svar. Om RoboCam får ett felaktigt svar på kommandot, eller inget svar inom en sekund, bryter RoboCam anslutningen och visar ett fel.

Så här ser byten ut i ett meddelande med kommandot CMD_START:

SSCTV

Här står en bokstav för en byte:

Här är ett exempel på ett meddelande med kommandot CMD_START i oktal form:

030000D101

När din robot tar emot kommandot måste den svara inom 1 sekund. Svaret är också en bytematris och ska se ut så här:

SSRTVC

Även här har jag markerat en byte med en bokstav. Så här ser det ut i byten:

Här är ett exempel på ett svar på kommandot CMD_START:

040000D20100

Kommandot «Anropssignal» (CMD_CALLSIGN)

När RoboCam får ett felfritt svar på kommandot CMD_START, med kontrollbyten, protokollversionen och teckenkodningen rätt angivna, börjar den fortsatta kommunikationen mellan roboten och RoboCam. Direkt därefter får roboten kommandot CMD_CALLSIGN. Det sker dock bara om en anropssignal och ett svar på den är angivna i RoboCams inställningar. Om ingen anropssignal eller inget svar är angivet skickas inte kommandot. På bilden nedan är till exempel anropssignalen «RoboCam» och svaret «Researcher» angivna i inställningarna.

Ange anropssignal och svar för roboten

Ett meddelande med kommandot CMD_CALLSIGN ser ut så här:

SSCAAA…0

Ett exempel på ett CMD_CALLSIGN-kommando med anropssignalen «RoboCam» i teckenkodningen US-ASCII ser ut så här:

090001526F626F43616D00

Som svar på kommandot ska du skicka strängen med svaret på anropssignalen som är angiven i RoboCams inställningar. Om någon annan sträng kommer tillbaka bryter RoboCam anslutningen. Svarsmeddelandet ser ut så här:

SSRAAA…0

Ett exempel med svaret «Researcher» på anropssignalen ser ut så här:

0C00005265736561726368657200

Kommandot «Kontroller» (CMD_CTRL)

När RoboCam har anslutit till ditt program, och efter kommandona CMD_START och CMD_CALLSIGN, börjar CMD_CTRL-kommandon komma. Det är kommandon från kontrollerna som användaren styr roboten med, det vill säga styrspakarna och tangentbordet. Kommandon kommer varje gång koordinaten för punkten där användarens finger rör vid en styrspak ändras, eller en tangents status (nedtryckt/inte nedtryckt) ändras, det vill säga när användaren styr roboten. Kommandon kommer bara om koordinaterna har ändrats eller en tangent på tangentbordet har tryckts ned eller släppts.

Ett meddelande med kommandot CMD_CTRL ser ut så här:

SSCJVJVJV…

Ett exempel på ett CMD_CTRL-kommando (kommandot betyder att X-axelns koordinat fick värdet 90, Y-axelns värdet -100 och tangenten med koden 89, det vill säga tangenten Y, trycktes ned):

060002005A019CFF59

För enkelhets skull är det bäst att direkt definiera konstanter för kontrollernas identifierare i koden:

//Styrspakarnas axlar.
const byte AXIS_X = 0;
const byte AXIS_Y = 1;
const byte AXIS_W = 2;
const byte AXIS_Z = 3;
const byte AXIS_A = 4;
const byte AXIS_B = 5;
const byte AXIS_C = 6;
const byte AXIS_D = 7;
 
//Tangentens tillstånd.
const byte KEY_PRESSED = 255; //Tangent nedtryckt.
const byte KEY_RELEASED = 254; //Tangent inte nedtryckt.

När ditt program tar emot ett CMD_CTRL-kommando får du direkt veta vad som har hänt med styrspakarna och tangenterna. Du kan då genast ändra robotens färdriktning, vrida en servo till rätt vinkel och så vidare. När du har bearbetat kommandot måste du skicka ett svar; det här är byten:

SSR

Svaret ser ut så här:

010000

Kommandot «Test» (CMD_TEST)

Kommandot CMD_TEST skickas ungefär en gång i sekunden för att kontrollera anslutningen. Om roboten inte svarar på kommandot anser RoboCam att förbindelsen med roboten har brutits. Så här ser ett meddelande med kommandot CMD_TEST ut:

SSC

Här är ett exempel på ett meddelande med kommandot CMD_TEST:

010003

Du måste svara på kommandot CMD_TEST inom 1 sekund, annars anser RoboCam att förbindelsen med roboten har brutits. Svarsformatet ska vara följande:

SSR

Här är ett exempel på ett svar på kommandot CMD_TEST:

010000

Kommandot «Stopp» (CMD_STOP)

Kommandot CMD_STOP skickas till roboten när roboten ska stoppas och återgå till utgångsläget. Det skickas om förbindelsen mellan telefonen med styrspakarna och RoboCam bryts, eller om du bryter anslutningen genom att trycka på den mittersta lila knappen i RoboCam. Vid det här kommandot ska roboten sluta röra sig och återställa servomotorerna till utgångsläget. Kommandots format är följande:

SSC

Här är ett exempel på ett meddelande med kommandot CMD_STOP:

0100FF

Svaret som förväntas på kommandot är följande:

SSR

Här är ett exempel på ett svar på kommandot CMD_STOP:

010000

Robotinställningar

Nu när vi har gått igenom kommunikationsprotokollet kan vi titta på de inställningar som tillkommit för icke-standardrobotar. Öppna inställningarna i RoboCam (den grå runda knappen till höger),

Inställningsknappen i RoboCam

välj sedan «Robot».

Robotinställningar i appen RoboCam

Robotinställningarna öppnas. Som du ser visar listan nu både inställningar för EV3-robotar och för icke-standardrobotar.

Listan över RoboCams robotinställningar

För att ändra inställningar du skapat tidigare väljer du dem helt enkelt i listan; för att lägga till nya inställningar för en icke-standardrobot trycker du på knappen «Lägg till» och väljer menyalternativet «Icke-standardrobot».

Menyalternativet "Icke-standardrobot" i RoboCam

Om du bestämmer dig för att skapa nya inställningar får du en tom inställningsskärm.

Tomma inställningar för icke-standardrobot i RoboCam

I artikeln beskriver jag inställningarna med utgångspunkt i inställningar jag skapat tidigare för att styra roboten du såg i videon högst upp i artikeln. Allra först anges robotens namn, som syns i listan över inställningar och på RoboCams huvudskärm om inställningarna är de aktuella. Därefter kommer en beskrivning, som bara syns i listan över inställningar.

Arduino-robotens inställningar i RoboCam

Om «Visa felsökningsinformation» är markerad visar klienten styrspakens koordinater medan den används, samt koderna för nedtryckta tangenter.

Om «Dölj styrspakar vid tangentbordsanvändning» är markerad försvinner styrspakarna på klienten, som i EV3-inställningarna, så fort någon tangent trycks ned på klienten. Så fort du klickar på skärmen med musen visas styrspakarna igen.

Därefter kommer inställningarna för anropssignal och svar. Texten som anges här används för kommandot CMD_CALLSIGN som beskrevs ovan.

Nedanför finns inställningarna för RoboCams 4 styrspakar. Inställningarna är desamma för alla styrspakar, så vi tittar på dem med den första styrspaken som exempel. Den första kryssrutan, «Synlighet», styr styrspakens synlighet; om den är avmarkerad visas styrspaken inte på klienten och fungerar inte.

Styrspaksinställningar i appen RoboCam

I listan «Form» kan du välja styrspakens form. Formerna är: vertikal, horisontell, rund, kvadratisk, pilar, vertikala pilar och horisontella pilar. Så här ser styrspakar av de beskrivna formerna ut:

RoboCams styrspakar

Hur styrspakarna fungerar beror på formen och beskrivs redan i artikeln «Styra en LEGO Mindstorms EV3-robot i förstaperson».

De följande två listorna väljer hur styrspakarna beter sig när du slutar röra vid dem. Det finns bara två alternativ: «Återgå till noll» och «Behåll position». I det första fallet återgår styrspaken till utgångsläget, det vill säga till noll, när du «släpper» den; i det andra stannar den där den är. Beteendet kan anges separat för styrspakens vertikala och horisontella axel.

Allra längst ner ställs tangenterna in. Kryssrutan «Aktiv» slår på eller av RoboCam-klientens känslighet för tangenttryckningar. Om du inte planerar att styra med tangentbordet rekommenderas det att avmarkera den för att spara batteri på klientenheten.

Lite längre ner kan du, om du trycker på inställningen «Tangenter», välja de tangenter vars tillstånd du tänker följa.

Ställa in tangenter för en icke-standardrobot i RoboCam

Sammantaget finns det mycket färre inställningar för en icke-standardrobot än för en EV3-robot, men de som finns fungerar som för EV3-roboten, så läs de tidigare artiklarna om RoboCam för mer detaljer.

Bygga Arduino-roboten

För att göra Arduino-roboten som styrs i förstaperson med RoboCam, som du ser i videon nedan, använde jag utbildningssatsen från Amperka samt ytterligare komponenter och delar: en Bluetooth-modul HC-06, extra plastdistanser, muttrar och brickor, två 3D-utskrivna delar för att hålla servomotorn, ett gem och två gummiband (sådana som används för sedlar).

Byggprocessen visas i snabbspolning i videon. Det är inget komplicerat med den. Om du bygger en sådan robot av Amperkas utbildningssats följer en bok med som beskriver hur man ansluter motorerna och hur man bygger en robot som följer en linje. Min robot är likadan som den i boken, men utan linjesensorer.

Jag bestämde mig för att fästa telefonen på enklaste sätt: nedtill är två distanser med skruvar fastskruvade och telefonen hålls mot dem med ett gummiband. Upptill hålls telefonen mot en skena, som den återigen är fäst vid med ett gummiband. Skenans andra ände är fäst vid en servo. I videon syns att telefonen lutar små vinklar, men genom att förlänga hävarmen kan du, om du vill, öka telefonens lutningsvinklar.

De färdiga modellerna för 3D-utskrift av servohållaren och skenan finns listade nedan:

Filer:
Servohållare (3D-modell)

Servohållare (3D-modell) för en robot byggd av Amperkas utbildningssats.

Servohållare

Datum: 06.10.2017 · Filstorlek: 76.41 KB

Skena (3D-modell)

Skena (3D-modell) för en robot byggd av Amperkas utbildningssats.

Skena för en robot byggd av Amperkas utbildningssats

Datum: 06.10.2017 · Filstorlek: 56.08 KB

Om din robotplattform är en annan blir din telefonhållare också en annan. I så fall är det inget problem att tillverka en egen hållare om du kan 3D-skriva ut. Mina egna 3D-modeller av servohållaren och skenan skapade jag i den molnbaserade 3D-editorn Tinkercad. Jag har redan beskrivit hur man arbetar med den i artikeln «Tinkercad – ett enkelt webbverktyg för 3D-konstruktion och 3D-utskrift» (på ryska).

För att upprepa mitt experiment behöver du också Arduino-skissen och RoboCam-inställningarna:

Arduino Explorer Version: från 10.09.2017

En skiss för att styra en hjulburen Arduino-robot med styrbar telefonhållare med hjälp av RoboCam.

Datum: 10.09.2017 · Filstorlek: 15.07 KB

RoboCam-inställningar för att styra Arduino Explorer Version: från 10.09.2017

RoboCam-inställningar för att styra Arduino Explorer.

Datum: 11.09.2017 · Filstorlek: 448 B

Alla RoboCam-versioner

Alla artiklar (samlingssida) · Field Manual