Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

MobBob:doe-het-zelf Arduino-robot bestuurd door Android-smartphone

Componenten en benodigdheden

Arduino Nano R3
× 1
HC-05 Bluetooth-module
× 1
SG90 Micro-servomotor
× 4
4xAA-batterijhouder
× 1
AA-batterijen
× 4

Benodigde gereedschappen en machines

Soldeerbout (algemeen)
3D-printer (algemeen)

Apps en online services

Arduino IDE

Over dit project

Ik heb deze robot gemaakt volgens de instructies op de website. Een geweldig idee voor symbiose tussen Arduino en Android.

MobBob is een smartphone-gestuurde robot. Door de kracht van je smartphone te benutten, is MobBob een lopende, pratende robot met spraakherkenning en computervisie.

3D-geprinte onderdelen:https://www.thingiverse.com/thing:715688

Android.apk-bestand:https://apkpure.com/mobbob/com.cevinius.MobBob

In de code wil je:

- Werk de pinvariabelen bij zodat ze overeenkomen met uw build

- Tweak het servocentrum, min en max waarden

- Stel "FRONT_JOINT_HIPS" in op 1 of -1, afhankelijk van de manier waarop uw heupservo's zijn gemonteerd. Ik monteer hem met de servo-as aan de voorkant van MobBob. Stel voor deze configuratie deze waarde in op 1.

Code

  • code
codeArduino
/* * =============================================================* MobBob-besturingsprogramma - Software Seriële Bluetooth-versie * door Kevin Chan (ook bekend als Cevinius) * =============================================================* * Dit programma stelt MobBob in staat om te worden bestuurd met behulp van seriële opdrachten. In deze versie van de code worden de *-opdrachten ontvangen via een seriële softwarepoort, met pinnen gedefinieerd in de #define bovenaan. * Dit betekent dat u elk Arduino-compatibel bord kunt gebruiken en een Bluetooth-kaart kunt aansluiten op de pinnen die zijn ingesteld voor * softwareserieel. (In tegenstelling tot de andere versie hiervan die is ontworpen voor het Bluno-bord van DFRobot.) * * Dit programma is lang en bevat 2 hoofdcomponenten - een soepel servo-animatieprogramma en een serieel * commando-parserprogramma. * * Animatiesysteem * ================* Het animatieprogramma is ontworpen om servo keyframe-arrays soepel te animeren. De code probeert zijn * best te doen om gemakkelijk te gebruiken te zijn. * * Het animatiesysteem zal slechts 1 commando in de wachtrij plaatsen. d.w.z. één opdracht kan worden uitgevoerd, * en één opdracht kan in de wachtrij worden geplaatst. Als u meer opdrachten verzendt, zullen ze de opdracht in de wachtrij overschrijven. * * Het animatiesysteem wacht standaard tot de huidige animatie is voltooid voordat de volgende wordt gestart. Dit * betekent dat als de animatiegegevens eindigen met de robot in zijn basishouding, alles soepel zal aansluiten. Om * dit te ondersteunen, heeft het animatiesysteem ook een functie waarbij een animatie een "afwerkingssequentie" * kan hebben om de robot terug in de basishouding te brengen. Deze functie wordt gebruikt voor de voorwaartse/achterwaartse animaties. * Die animaties hebben een laatste reeks die de robot terug in de basishouding brengt. * * Wanneer een animatie klaar is met afspelen, stuurt het animatiesysteem een ​​antwoordreeks naar de seriële poort. * Hierdoor weten de bellers wanneer de gevraagde animaties zijn afgespeeld. Dit is handig * voor gebruikers om animaties in volgorde te zetten - wachten tot de ene klaar is voordat ze aan de andere beginnen. * * De animatiecode heeft veel variabelen om dingen aan te passen. bijv. Updatefrequentie, arduino-pinnen, enz. * * Het animatiegegevensarrayformaat is ook ontworpen om gemakkelijk met de hand te kunnen worden bewerkt. * * Command Parser * ==============* Dit systeem ontleedt de seriële commando's en verwerkt ze. De commando's omvatten een voor het direct * instellen van servoposities, evenals commando's voor het activeren van vooraf gedefinieerde animaties en wandelingen. * * Gebruikers die zich geen zorgen willen maken over de details van het lopen, kunnen dus gewoon de vooraf gedefinieerde wandelingen/animaties gebruiken. * En gebruikers die volledige controle over de servo's willen (om on-the-fly nieuwe animaties te maken) kunnen dat ook doen. * * Zoals hierboven vermeld, kunnen deze commando's interactief worden gebruikt vanaf de Arduino Serial Monitor. Ze kunnen ook * worden verzonden via Bluetooth LE (bij gebruik van een Bluno). De telefoon-app stuurt de opdrachten via Bluetooth LE naar de * Bluno. * * Algemene opdrachten:* ----------------- * Gereed/OK-controle: * Statuscontrole. Het antwoord wordt onmiddellijk teruggestuurd om te controleren of de controller werkt. * * Servo instellen: * tijd - tijd om te tween naar gespecificeerde hoeken, 0 springt onmiddellijk naar hoeken * leftHip - microsecs vanaf het midden. -ve is heup in, +ve is heup uit * leftFoot - microsecs van plat. -ve is voet naar beneden, +ve is voet omhoog * rechterheup - microsecs vanaf het midden. -ve is heup in, +ve is heup uit * rightFoot - microsecs van plat. -ve is voet omlaag, +ve is voet omhoog * Dit commando wordt gebruikt om volledige controle over de servo's te krijgen. U kunt de robot gedurende de opgegeven duur van zijn * huidige pose naar de opgegeven pose tween. * * Stop/Reset: * Stopt de robot na de huidige animatie. Kan worden gebruikt om animaties die op loop * zijn ingesteld, voor onbepaalde tijd te stoppen. Dit kan ook worden gebruikt om de robot in zijn basishouding te zetten (recht staand) * * Onmiddellijk stoppen: * Stopt de robot onmiddellijk zonder te wachten om de huidige animatie te voltooien. Dit * onderbreekt de huidige animatie van de robot. Mogelijk is de robot midden in een animatie * en in een onstabiele houding, dus wees voorzichtig bij het gebruik hiervan. * * Standaard Walk-commando's:* ----------------------- * Vooruit:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Achteruit:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Draai naar links:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Draai naar rechts:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * * Leuke animatie-opdrachten:* ----------------------- * Hoofd schudden:, -1 betekent continu, 0 of geen param is hetzelfde als 1 keer. * * Bounce:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * * Wobble:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Wobble Links:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Wobble Rechts:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * * Tik op Voeten:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Tik op Linkervoet:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Tik op Rechtervoet:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * * Shake Legs:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Linkerbeen schudden:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * Rechterbeen schudden:, -1 betekent continu, 0 of geen parameter is hetzelfde als 1 keer. * * De code stuurt ook een antwoordreeks terug over Serial wanneer de opdrachten * zijn uitgevoerd. * * Als de opdracht normaal is voltooid, is de antwoordreeks de opdrachtcode zonder * parameters. bijv. Wanneer het klaar is met vooruitgaan, stuurt het het antwoord "". * * Als een opdracht werd onderbroken met , is de huidige animatie mogelijk halverwege gestopt. * In dit geval kan de robot zich in een vreemde middenpositie bevinden en is het mogelijk dat finishAnims niet * is gespeeld. Om de gebruiker te laten weten dat dit is gebeurd, heeft de antwoordreeks de * parameter -1. Als een wandeling bijvoorbeeld halverwege werd gestopt met behulp van , zou de antwoordreeks *  zijn om aan te geven dat de wandeling is gestopt, maar halverwege is gestopt. * (Opmerking:als u  gebruikt om te stoppen, wordt gewacht tot de huidige animatiecyclus is voltooid * voordat u stopt. In dat geval worden animaties dus niet halverwege gestopt.) * * Omdat de antwoorden worden verzonden na een animatie is voltooid, kan de afzender van het commando * de responsstrings opzoeken om te bepalen wanneer de robot klaar is voor een nieuw commando. * bijv. Als je het commando  gebruikt, wordt de response string pas verzonden nadat alle 3 stappen * (en finish anim) zijn voltooid. De afzender van de opdracht kan dus wachten op de string response * voordat hij de robot vertelt het volgende te doen. */ #include #include //-------------------------------- -------------------------------------------------- // Snelheid van seriële communicatie - Stel dit in voor uw seriële (bluetooth) kaart.//------------------------------- -------------------------------------------------- -// Seriële communicatiesnelheid met het bluetooth-bord.// Sommige borden zijn standaard ingesteld op 9600. Het bord dat ik heb heeft een standaardwaarde van 115200. #define SERIAL_SPEED 115200// Stel een software seriële poort in op deze pinnen.const int rxPin =11; // pin gebruikt om dataconst int txPin =12 te ontvangen; // pin gebruikt om data te verzendenSoftwareSerial softwareSerial(rxPin, txPin);//---------------------------------- ------------------------------------------------// Arduino-pinnen instellen - Stel deze in voor uw specifieke robot.//------------------------------------- ---------------------------------------------const int SERVO_LEFT_HIP =5;const int SERVO_LEFT_FOOT =2;const int SERVO_RIGHT_HIP =3;const int SERVO_RIGHT_FOOT =4;// Ik wil dat deze code bruikbaar is op alle 4-servo tweevoeters! (Net als Bob, MobBob)// Ik merkte dat sommige builds de hippe servo's op een andere// manier monteren dan hoe ik MobBob's deed, dus met deze instelling kun je de code configureren// voor beide bouwstijlen.// 1 voor MobBob-stijl naar voren gerichte heupen (gewricht naar voren)// -1 voor naar achteren gerichte heupen in bob-stijl (gewricht naar achteren)#define FRONT_JOINT_HIPS 1//------------------- -------------------------------------------------- -------------// Servo Max/Min/Centre constanten - Stel deze in voor uw specifieke robot.//------------------ -------------------------------------------------- --------------const int LEFT_HIP_CENTRE =1580;const int LEFT_HIP_MIN =LEFT_HIP_CENTRE - 500;const int LEFT_HIP_MAX =LEFT_HIP_CENTRE + 500;const int LEFT_HIP_MIN =LEFT_HIP_CENTRE - 500;const int LEFT_HIP_MAX =LEFT_HIP_CENTRE + 500;const int LEFT_HIP_FOOT_CENTRE const int LEFT_FOOT_MAX =LEFT_FOOT_CENTRE + 500;const int RIGHT_HIP_CENTRE =1500;const int RIGHT_HIP_MIN =RIGHT_HIP_CENTRE - 500;const int RIGHT_HIP_MAX =RIGHT_HIP_CENTRE + 500;const int RIGHT_ 465;const int RIGHT_FOOT_MIN =RIGHT_FOOT_CENTRE - 500;const int RIGHT_FOOT_MAX =RIGHT_FOOT_CENTRE + 500;//----------------------------- ------------------------------------------------// Helperfuncties om gewrichtswaarden op een gebruiksvriendelijkere manier te helpen berekenen.// U kunt de tekens hier aanpassen als de servo's op een andere manier zijn ingesteld.// Hier bijwerken betekent dat de animatiegegevens niet hoeven te worden gewijzigd als de // servo's zijn anders ingesteld.// (Bijv Originele Bob's heupservo's zijn omgekeerd aan die van MobBob.)//// (Ook vind ik het moeilijk om de tekens te onthouden die voor elke servo moeten worden gebruikt, omdat ze // verschillend zijn voor linker/rechter heupen en voor linker/rechter voeten.) //------------------------------------------------ ------------------------------int LeftHipCentre() { return LEFT_HIP_CENTRE; }int LeftHipIn(int millisecs) { return LEFT_HIP_CENTRE + (FRONT_JOINT_HIPS * millisecs); }int LeftHipOut (int millisecs) { return LEFT_HIP_CENTRE - (FRONT_JOINT_HIPS * millisecs); }int RightHipCentre() { return RIGHT_HIP_CENTRE; }int RightHipIn (int millisecs) { return RIGHT_HIP_CENTRE - (FRONT_JOINT_HIPS * millisecs); }int RightHipOut (int millisecs) { return RIGHT_HIP_CENTRE + (FRONT_JOINT_HIPS * millisecs); }int LeftFootFlat() { return LEFT_FOOT_CENTRE; }int LeftFootUp(int millisecs) { return LEFT_FOOT_CENTRE - millisecs; }int LeftFootDown(int millisecs) { return LEFT_FOOT_CENTRE + millisecs; }int RightFootFlat() { retourneer RIGHT_FOOT_CENTRE; }int RightFootUp (int millisecs) { return RIGHT_FOOT_CENTRE + millisecs; }int RightFootDown(int millisecs) { return RIGHT_FOOT_CENTRE - millisecs; }//----------------------------------------------- -----------------------------------// Keyframe-animatiegegevens voor standaard looppatroon en andere servo-animaties// // Indeling is { , ​​, , ,  }// milliseconden - tijd om te tween naar de posities van dit keyframe. bijv. 500 betekent dat het 500 ms duurt om van de// robotpositie aan het begin van dit frame naar de positie gespecificeerd in dit frame te gaan// leftHipMicros - positie van linkerheup in servomicrosec.// leftFootMicros - positie van linkerheup in servo microsec.// rightHipMicros - positie van linkerheup in servomicrosec.// rightFootMicros - positie van linkerheup in servomicrosec.// // De servomicrowaarden ondersteunen een speciale waarde van -1. Als deze waarde wordt gegeven, vertelt het// de animatiecode om deze servo in dit keyframe te negeren. d.w.z. die servo zal// blijft in de positie die hij had aan het begin van dit keyframe.//// Ook het eerste element in de animatiegegevens is speciaal. Het is een metadata-element.// Het eerste element is { , 0, 0, 0, 0 }, dat ons het aantal frames// in de animatie vertelt. Het eerste daadwerkelijke keyframe bevindt zich dus in animData[1] en het laatste keyframe// bevindt zich in animData[]. (Waarbij  de waarde is in animData[0][0].)//----------------------------- -------------------------------------------------- ---// Constanten om de toegang tot de keyframe-arrays menselijker te maken.const int TWEEN_TIME_VALUE =0;const int LEFT_HIP_VALUE =1;const int LEFT_FOOT_VALUE =2;const int RIGHT_HIP_VALUE =3;const int RIGHT_FOOT//VALUE =4; in de loopganganimatie data.const int FOOT_DELTA =150;const int HIP_DELTA =FRONT_JOINT_HIPS * 120;// Gaat naar de standaard rechtopstaande positie. Gebruikt door stopAnim().int standStraightAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 1, 0, 0, 0, 0 }, // Voeten plat, Voeten even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};// Voorafgaand hieraan moet de robot Voeten plat, voeten gelijk (dwz standStraightAnim).int walkForwardAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 8, 0, 0, 0, 0 }, // Naar links kantelen, Voeten even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt naar links, rechtervoet vooruit {300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Voeten plat, Rechtervoet vooruit {300, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat() }, // Tilt naar rechts, Rechter voet naar voren {300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootUp(FOOT_DELTA)}, // Tilt naar rechts, Feet even {300, LeftHipCentre (), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt naar rechts, Linker voet naar voren {300, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA)} , // Voeten plat, linkervoet naar voren {300, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat()}, // Tilt naar links, linkervoet naar voren {300, LeftHipOut(HIP_DEL) TA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA) }};// Voorafgaand hieraan moet de robot naar Feet Flat, Feet Even (d.w.z. standStraightAnim).int walkBackwardAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 8, 0, 0, 0, 0 }, // Naar links kantelen, Voeten even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt naar links, Left foot vooruit {300, LeftHipOut(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Voeten plat, Linkervoet vooruit {300, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat()}, // Tilt naar rechts, Linker voet naar voren {300, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA)}, // Tilt naar rechts, Feet even {300, LeftHipCentre (), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt naar rechts, Right foot forward {300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootUp(FOOT_DELTA)} , // Voeten plat, rechtervoet naar voren {300, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat()}, // Tilt naar links, rechtervoet naar voren {300, LeftHipIn(HIP_DELTA) ), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA) }};// Loop anim beëindigen brengt de robot vanaf het einde van walkForwardAnim/walkBackwardAnim terug naar standStraightAnim.int walkEndAnim[][5] ={ // Metadata . Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Naar links kantelen, Voeten even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Voeten plat, Voeten even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};// Breng de robot hiervoor eerst naar Feet Flat, Feet Even (dwz standStraightAnim).int turnLeftAnim[][5] ={ / / Metagegevens. Het eerste element is het aantal frames. { 6, 0, 0, 0, 0 }, // Tilt naar links, Feet even { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt to left, Turn left heup, draai rechts heup { 300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Voeten plat, draai links heup, Draai rechts heup { 300, LeftHipIn(HIP_DELTA), LeftFootFlat (), RightHipIn(HIP_DELTA), RightFootFlat() }, // Tilt naar rechts, Draai links heup, Draai rechts heup {300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA)}, // Naar rechts kantelen, Voeten even {300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Voeten plat, Voeten even {300, LeftHipCentre(), LeftFootFlat(), RightHipCentre( ), RightFootFlat() }};// Breng de robot eerst naar Feet Flat, Feet Even (dwz standStraightAnim).int turnRightAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. {6, 0, 0, 0, 0 }, // Tilt naar rechts, Feet even {300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt naar rechts, Turn left heup, draai rechts heup { 300, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootUp(FOOT_DELTA)}, // Voeten plat, draai links heup, Draai rechts heup { 300, LeftHipIn(HIP_DELTA), LeftFootFlat (), RightHipIn(HIP_DELTA), RightFootFlat() }, // Tilt naar links, Draai links heup, Draai rechts heup {300, LeftHipIn(HIP_DELTA), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Naar links kantelen, Voeten even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Voeten plat, Voeten even {300, LeftHipCentre(), LeftFootFlat(), RightHipCentre( ), RightFootFlat() }};// Schud hoofdanimatie. Links rechts snel om het schudden van het hoofd na te bootsen.int shakeHeadAnim [][5] ={ // Metadata. Het eerste element is het aantal frames. { 4, 0, 0, 0, 0 }, // Voeten plat, links draaien { 150, LeftHipOut(HIP_DELTA), LeftFootFlat(), RightHipIn(HIP_DELTA), RightFootFlat() }, // Voeten plat, Voeten even { 150 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // Voeten plat, Draai rechts {150, LeftHipIn(HIP_DELTA), LeftFootFlat(), RightHipOut(HIP_DELTA), RightFootFlat() }, // Voeten plat, Voeten even { 150, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Wobble anim. Kantel naar links en rechts om een ​​leuke wobble.int te doen wobbleAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 4, 0, 0, 0, 0 }, // Tilt left, Feet even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Feet flat, Feet even {300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // Tilt rechts, Feet even {300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Feet plat, Voeten even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Wobble left anim. Kantel naar links en naar achteren.int wobbleLeftAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Tilt links, Feet even { 300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Voeten plat, Feet even {300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Wobble rechts anim. Kantel naar rechts en terug.int wobbleRightAnim [][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Rechts kantelen, Voeten even { 300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Voeten plat, Voeten even {300 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Tap feet anim. Tik op beide voeten.int tapFeetAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Hef beide voeten op, Voeten even { 500, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Voeten plat, Voeten even { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Tik op linkervoet anim.int tapLeftFootAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Linkervoet omhoog, Voeten even { 500, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootFlat() }, // Voeten plat, Voeten even { 500 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Tik op rechtervoet anim.int tapRightFootAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Rechtervoet omhoog, Voeten even { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootUp(FOOT_DELTA) }, // Voeten plat, Voeten even { 500 , LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Stuiteren op en neer anim.int bounceAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. { 2, 0, 0, 0, 0 }, // Hef beide voeten op, Voeten even { 500, LeftHipCentre(), LeftFootDown(300), RightHipCentre(), RightFootDown(300)}, // Voeten plat, Voeten even { 500, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() },};// Shake Legs Animation.int shakeLegsAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. {14, 0, 0, 0, 0}, // Tilt left, Feet even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt left, Right hip in { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) } , // Kantel links, rechter heup naar buiten {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA) , RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt links, Right hip in {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Voeten plat, Voeten even {300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, // Kantelinstallatie ht, Voeten even {300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Linker heup in {100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre() , RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Left hip out {100, LeftHipOut(HIP_DELTA) ), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Voeten plat , Feet even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Schud linkerbeen Animation.int shakeLeftLegAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. {12, 0, 0, 0, 0}, // Tilt rechts, Feet even {300, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Left heup in { 100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA) } , // Tilt rechts, Linker heup naar buiten {100, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA) , RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Left heup in {100, LeftHipIn(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even { 100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Left hip out {100, LeftHipOut(HIP_DELTA), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFo otUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Left heup in {100, LeftHipIn(HIP_DELTA) , LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Tilt rechts, Feet even {100, LeftHipCentre(), LeftFootDown(FOOT_DELTA), RightHipCentre(), RightFootUp(FOOT_DELTA)}, // Voeten plat, Voeten even {300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() } };// Schud rechterbeen Animation.int shakeRightLegAnim[][5] ={ // Metadata. Het eerste element is het aantal frames. {12, 0, 0, 0, 0}, // Tilt left, Feet even {300, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt left, Right hip in { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA) } , // Kantel links, rechter heup naar buiten {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA) , RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt links, Right hip in {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt links, Right hip out {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipOut(HIP_DELTA), RightFootDown (FOOT_DELTA) }, // Tilt links, Feet even { 100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Tilt links, Right hip in {100, LeftHipCentre(), LeftFootUp (FOOT_DELTA), RightHipIn(HIP_DELTA), RightFootDown(FOOT_DELTA)}, // Tilt left, Feet even {100, LeftHipCentre(), LeftFootUp(FOOT_DELTA), RightHipCentre(), RightFootDown(FOOT_DELTA)}, // Voeten plat, Voeten even { 300, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }, };//------------------------- -------------------------------------------------- -------// Speciale dynamische animatiegegevens voor het instellen/tween van servoposities.//---------------------------- -------------------------------------------------- ----// Dit zijn 2 speciale anim-gegevens die we gebruiken voor de functie SetServos(). Ze hebben// een enkel frame. Die zullen de gegevens in deze animgegevens veranderen en ze afspelen om // de servos.int te verplaatsen setServosAnim1[][5] ={ // Metadata. Het eerste element is het aantal frames. { 1, 0, 0, 0, 0 }, // Tilt left, Feet even { 0, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};int setServosAnim2[][5] ={ // Metadata. First element is number of frames. { 1, 0, 0, 0, 0 }, // Tilt left, Feet even { 0, LeftHipCentre(), LeftFootFlat(), RightHipCentre(), RightFootFlat() }};//----------------------------------------------------------------------------------// Servo Variables//----------------------------------------------------------------------------------Servo servoLeftHip;Servo servoLeftFoot;Servo servoRightHip;Servo servoRightFoot;//----------------------------------------------------------------------------------// State variables for playing animations.//----------------------------------------------------------------------------------// Milliseconds between animation updates.const int millisBetweenAnimUpdate =20;// Time when we did the last animation update.long timeAtLastAnimUpdate;// Related to currently playing anim.int (*currAnim)[5]; // Current animation we're playing.int (*finishAnim)[5]; // Animation to play when the currAnim finishes or is stopped.long timeAtStartOfFrame; // millis() at last keyframe - frame we're lerping fromint targetFrame; // Frame we are lerping toint animNumLoops; // Number of times to play the animation. -1 means loop forever.char animCompleteStr[3] ="--"; // This is a 2 character string. When the anim is complete, // we print out the status as "<" + animComplereStr + ">".// Related to anim queue. I.e. Next anim to play.bool animInProgress; // Whether an animation is playingint (*nextAnim)[5]; // This is the next animation to play once the current one is done. // i.e. It's like a queue of size 1! // If curr is non-looping, we play this at the end of the current anim. // If curr is looping, this starts at the end of the current loop, // replacing curr anim. // If nothing is playing, this starts right away. int (*nextFinishAnim)[5]; // This is the finish animation for the queued animation.int nextAnimNumLoops; // Number of times to play the animation. -1 means loop forever.char nextAnimCompleteStr[3] ="--"; // This is a 2 character string. When the anim is complete, // we print out the status as "<" + animComplereStr + ">".bool interruptInProgressAnim; // Whether to change anim immediately, interrupting the current one.// Curr servo positionsint currLeftHip;int currLeftFoot;int currRightHip;int currRightFoot;// Servo positions at start of current keyframeint startLeftHip;int startLeftFoot;int startRightHip;int startRightFoot;//-------------------------------------------------------------------------------// Parser Variables//-------------------------------------------------------------------------------// Constant delimiter tag charsconst char START_CHAR ='<';const char END_CHAR ='>';const char SEP_CHAR =',';// Constants and a variable for the parser state.const int PARSER_WAITING =0; // Waiting for '<' to start parsing.const int PARSER_COMMAND =1; // Reading the command string.const int PARSER_PARAM1 =2; // Reading param 1.const int PARSER_PARAM2 =3; // Reading param 2.const int PARSER_PARAM3 =4; // Reading param 3.const int PARSER_PARAM4 =5; // Reading param 3.const int PARSER_PARAM5 =6; // Reading param 3.const int PARSER_EXECUTE =7; // Finished parsing a command, so execute it.// Current parser state.int currParserState =PARSER_WAITING; // String for storing the command. 2 chars for the command and 1 char for '\0'.// We store the command here as we're parsing.char currCmd[3] ="--";// For tracking which letter we are in the command.int currCmdIndex;// Max command length.const int CMD_LENGTH =2;// Current param values. Store them here after we parse them.int currParam1Val;int currParam2Val;int currParam3Val;int currParam4Val;int currParam5Val;// Variable for tracking which digit we're parsing in a param.// We use this to convert the single digits back into a decimal value.int currParamIndex;// Whether the current param is negative.boolean currParamNegative;// Max parameter length. Stop parsing if it exceeds this.const int MAX_PARAM_LENGTH =6;//===============================================================================// Arduino setup() and loop().//===============================================================================void setup() { // Setup the main serial port softwareSerial.begin(SERIAL_SPEED); // Setup the Servos servoLeftHip.attach( SERVO_LEFT_HIP, LEFT_HIP_MIN, LEFT_HIP_MAX); servoLeftFoot.attach( SERVO_LEFT_FOOT, LEFT_FOOT_MIN, LEFT_FOOT_MAX); servoRightHip.attach( SERVO_RIGHT_HIP, RIGHT_HIP_MIN, RIGHT_HIP_MAX); servoRightFoot.attach(SERVO_RIGHT_FOOT, RIGHT_FOOT_MIN, RIGHT_FOOT_MAX); // Set things up for the parser. setup_Parser(); // Set things up for the animation code. setup_Animation();}void loop() { // Update the parser. loop_Parser(); // Update the animation. loop_Animation();}//===============================================================================// Related to the parser//===============================================================================// Sets up the parser stuff. Called in setup(). Should not be called elsewhere.void setup_Parser(){ // Wait for first command. currParserState =PARSER_WAITING; // Print this response to say we've booted and are ready. softwareSerial.println("");}// Loop() for the parser stuff. Called in loop(). Should not be called elsewhere.void loop_Parser(){ //--------------------------------------------------------- // PARSER // // If there is data, parse it and process it. //--------------------------------------------------------- // Read from pin serial port and write it out on USB port. if (softwareSerial.available()> 0) { char c =softwareSerial.read(); // If we're in WAITING state, look for the START_CHAR. if (currParserState ==PARSER_WAITING) { // If it's the START_CHAR, move out of this state... if (c ==START_CHAR) { // Start parsing the command. currParserState =PARSER_COMMAND; // Reset thing ready for parsing currCmdIndex =0; currCmd[0] ='-'; currCmd[1] ='-'; currParam1Val =0; currParam2Val =0; currParam3Val =0; currParam4Val =0; currParam5Val =0; } // Otherwise, stay in this state. } // In the state to look for the command. else if (currParserState ==PARSER_COMMAND) { // Else if it's a separator, parse parameter 1. But make sure it's not // empty, or else it's a parse error. if (c ==SEP_CHAR) { if (currCmdIndex ==CMD_LENGTH) { currParserState =PARSER_PARAM1; currParamIndex =0; currParamNegative =false; } else { currParserState =PARSER_WAITING; } } // Else if it's the end char, there are no parameters, so we're ready to // process. But make sure it's not empty. Otherwise, it's a parse error. else if (c ==END_CHAR) { if (currCmdIndex ==CMD_LENGTH) { currParserState =PARSER_EXECUTE; } else { currParserState =PARSER_WAITING; } } // If we've got too many letters here, we have a parse error, // so abandon and go back to PARSER_WAITING else if ( (currCmdIndex>=CMD_LENGTH) || (c <'A') || (c> 'Z') ) { currParserState =PARSER_WAITING; } // Store the current character. else { currCmd[currCmdIndex] =c; currCmdIndex++; } } // In the state to parse param 1. else if (currParserState ==PARSER_PARAM1) { // Else if it's a separator, parse parameter 1. if (c ==SEP_CHAR) { if (currParamNegative) { currParam1Val =-1 * currParam1Val; } currParserState =PARSER_PARAM2; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam1Val =-1 * currParam1Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam1Val =(currParam1Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 2. else if (currParserState ==PARSER_PARAM2) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam2Val =-1 * currParam2Val; } currParserState =PARSER_PARAM3; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam2Val =-1 * currParam2Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam2Val =(currParam2Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 3. else if (currParserState ==PARSER_PARAM3) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam3Val =-1 * currParam3Val; } currParserState =PARSER_PARAM4; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam3Val =-1 * currParam3Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam3Val =(currParam3Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 4. else if (currParserState ==PARSER_PARAM4) { // Else if it's a separator, parse parameter 2. if (c ==SEP_CHAR) { if (currParamNegative) { currParam4Val =-1 * currParam4Val; } currParserState =PARSER_PARAM5; currParamIndex =0; currParamNegative =false; } // Else if it's the end char, there are no parameters, so we're ready to // process. else if (c ==END_CHAR) { if (currParamNegative) { currParam4Val =-1 * currParam4Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam4Val =(currParam4Val * 10) + currDigitVal; currParamIndex++; } } // In the state to parse param 5. else if (currParserState ==PARSER_PARAM5) { // If it's the end char, there are no parameters, so we're ready to // process. if (c ==END_CHAR) { if (currParamNegative) { currParam5Val =-1 * currParam5Val; } currParserState =PARSER_EXECUTE; } // Check for negative at the start. else if ( (currParamIndex ==0) &&(c =='-') ) { currParamNegative =true; currParamIndex++; } // If it's too long, or the character is not a digit, then it's // a parse error, so abandon and go back to PARSER_WAITING. else if ( (currParamIndex>=MAX_PARAM_LENGTH) || (c <'0') || (c> '9') ) { currParserState =PARSER_WAITING; } // It's a valid character, so process it. else { // Shift existing value across and add new digit at the bottom. int currDigitVal =c - '0'; currParam5Val =(currParam5Val * 10) + currDigitVal; currParamIndex++; } } //--------------------------------------------------------- // PARSER CODE HANDLER (Still part of Parser, but section that // processes completed commands) // // If the most recently read char completes a command, // then process the command, and clear the state to // go back to looking for a new command. // // The parsed items are stored in:// currCmd, currParam1Val, currParam2Val, currParam3Val, // currParam4Val, currParam5Val //--------------------------------------------------------- if (currParserState ==PARSER_EXECUTE) { // Ready/OK Check: if ((currCmd[0] =='O') &&(currCmd[1] =='K')) { softwareSerial.println(""); } // Set Servo: // time - time to tween to specified angles // leftHip - microsecs from centre. -ve is hip in, +ve is hip out // leftFoot - microsecs from flat. -ve is foot down, +ve is foot up // rightHip - microsecs from centre. -ve is hip in, +ve is hip out // rightFoot - microsecs from flat. -ve is foot down, +ve is foot up else if ((currCmd[0] =='S') &&(currCmd[1] =='V')) { int tweenTime =currParam1Val; if (currParam1Val <0) { tweenTime =0; } SetServos(tweenTime, currParam2Val, currParam3Val, currParam4Val, currParam5Val, "SV"); } // Stop/Reset:, Stops current anim. Also can be used to put robot into reset position. else if ((currCmd[0] =='S') &&(currCmd[1] =='T')) { StopAnim("ST"); } // Stop Immediate: else if ((currCmd[0] =='S') &&(currCmd[1] =='I')) { StopAnimImmediate("SI"); } // Forward:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='F') &&(currCmd[1] =='W')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(walkForwardAnim, walkEndAnim, numTimes, "FW"); } // Backward:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='B') &&(currCmd[1] =='W')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(walkBackwardAnim, walkEndAnim, numTimes, "BW"); } // Turn Left:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='T')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(turnLeftAnim, NULL, numTimes, "LT"); } // Turn Right:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='R') &&(currCmd[1] =='T')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(turnRightAnim, NULL, numTimes, "RT"); } // Shake Head:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='S') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeHeadAnim, NULL, numTimes, "SX"); } // Bounce:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='B') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(bounceAnim, NULL, numTimes, "BX"); } // Wobble:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleAnim, NULL, numTimes, "WX"); } // Wobble Left:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleLeftAnim, NULL, numTimes, "WY"); } // Wobble Right:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='W') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(wobbleRightAnim, NULL, numTimes, "WZ"); } // Tap Feet:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapFeetAnim, NULL, numTimes, "TX"); } // Tap Left Foot:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapLeftFootAnim, NULL, numTimes, "TY"); } // Tap Right Foot:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='T') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(tapRightFootAnim, NULL, numTimes, "TZ"); } // Shake Legs:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='X')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeLegsAnim, NULL, numTimes, "LX"); } // Shake Left Leg:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='Y')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeLeftLegAnim, NULL, numTimes, "LY"); } // Shake Right Leg:, -1 means continuous, 0 or no param is the same as 1 time. else if ((currCmd[0] =='L') &&(currCmd[1] =='Z')) { int numTimes =currParam1Val; if (currParam1Val <0) { numTimes =-1; } PlayAnimNumTimes(shakeRightLegAnim, NULL, numTimes, "LZ"); } //-------------------------------------------------- // Clear the state and wait for the next command! // This must be done! //-------------------------------------------------- currParserState =PARSER_WAITING; } }}//===============================================================================// Related to playing servo animations.//===============================================================================// Call this to play the given animation once. Pass in NULL if there is no finishAnim.void PlayAnim(int animToPlay[][5], int finishAnim[][5], const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(animToPlay, finishAnim, 1, completeStr);}// Call this to loop the given animation. Pass in NULL if there is no finishAnim.void LoopAnim(int animToPlay[][5], int finishAnim[][5], const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(animToPlay, finishAnim, -1, completeStr);}// Call this to play the given animation the specified number of times. // -1 number of times will make it loop forever.// Pass in NULL if there is no finishAnim.void PlayAnimNumTimes(int animToPlay[][5], int finishAnim[][5], int numTimes, const char *completeStr){ // Put this in the queue. nextAnim =animToPlay; nextFinishAnim =finishAnim; nextAnimNumLoops =numTimes; // Save the completeStr if (completeStr ==NULL) { nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; } else { nextAnimCompleteStr[0] =completeStr[0]; nextAnimCompleteStr[1] =completeStr[1]; }}// Stop after the current animation.void StopAnim(const char *completeStr){ // Put this in the queue. PlayAnimNumTimes(standStraightAnim, NULL, 1, completeStr);}// Stop immediately and lerp robot to zero position, interrupting // any animation that is in progress.void StopAnimImmediate(const char *completeStr){ // Put this in the queue. interruptInProgressAnim =true; PlayAnimNumTimes(standStraightAnim, NULL, 1, completeStr);}// Moves servos to the specified positions. Time 0 will make it immediate. Otherwise,// it'll tween it over a specified time.// For positions, 0 means centered.// For hips, -ve is hip left, +ve is hip right// For feet, -ve is foot down, +ve is foot upvoid SetServos(int tweenTime, int leftHip, int leftFoot, int rightHip, int rightFoot, const char* completeStr){ // Save the completeStr if (completeStr ==NULL) { nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; } else { nextAnimCompleteStr[0] =completeStr[0]; nextAnimCompleteStr[1] =completeStr[1]; } // Decide which tween data we use. We don't want to over-write the one that is // in progress. We have and reuse these to keep memory allocation fixed. int (*tweenServoData)[5]; if (currAnim !=setServosAnim1) { tweenServoData =setServosAnim1; } else { tweenServoData =setServosAnim2; } // Set the tween information into the animation data. tweenServoData[1][TWEEN_TIME_VALUE] =tweenTime; tweenServoData[1][LEFT_HIP_VALUE] =LeftHipIn(leftHip); tweenServoData[1][LEFT_FOOT_VALUE] =LeftFootUp(leftFoot); tweenServoData[1][RIGHT_HIP_VALUE] =RightHipIn(rightHip); tweenServoData[1][RIGHT_FOOT_VALUE] =RightFootUp(rightFoot); // Queue this tween to be played next. PlayAnim(tweenServoData, NULL, completeStr);}// Set up variables for animation. This is called in setup(). Should be not called by anywhere else.void setup_Animation(){ // Set the servos to the feet flat, feet even position. currLeftHip =LEFT_HIP_CENTRE; currLeftFoot =LEFT_FOOT_CENTRE; currRightHip =RIGHT_HIP_CENTRE; currRightFoot =RIGHT_FOOT_CENTRE; UpdateServos(); // Set the "start" positions to the current ones. So, when // we pay the next anim, we will tween from the current positions. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // No animation is playing yet, and nothing in the queue yet. timeAtLastAnimUpdate =millis(); animInProgress =false; interruptInProgressAnim =false; currAnim =NULL; finishAnim =NULL; nextAnim =NULL; nextFinishAnim =NULL;}// Loop function for processing animation. This is called in every loop(). Should be be called by anywhere else.//// NOTE:The way looping animations work is that they basically add themselves back to the queue// when a cycle is done, and if there's nothing already queued up! This way, looping animations// work in a similar way to single-play animations, and fits into the queueing system.void loop_Animation(){ // Get the time at the start of this frame. long currTime =millis(); //-------------------------------------------------------------------------------------- // Decide if we want to perform the animation update. We don't execute this every frame. //-------------------------------------------------------------------------------------- if (timeAtLastAnimUpdate + millisBetweenAnimUpdate> currTime) { // Not yet time to do an anim update, so jump out. opbrengst; } else { // We reset the timer, and then proceed below to handle the current anim update. timeAtLastAnimUpdate =currTime; } //-------------------------------------------------------------------------------------- // Decide if we need to setup and start a new animation. We do if there's no anim // playing or we've been asked to interrupt the anim. //-------------------------------------------------------------------------------------- if ( (nextAnim !=NULL) &&(!animInProgress || interruptInProgressAnim) ) { // If this was an interrupt, we also set the "start" servo positions // to the current ones. This way, the animation system will tween from the // current positions. if (interruptInProgressAnim) { // This is the place to notify someone of an animation finishing after getting interrupted // Print the command string we just finished. -1 parameter indicates it was interrupted. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(",-1>"); // Set the "start" positions to the current ones. So, when // we pay the next anim, we will tween from the current positions. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // We've handled any interrupt request, so clear the flag. interruptInProgressAnim =false; } // Store the animation we are now playing. currAnim =nextAnim; finishAnim =nextFinishAnim; animCompleteStr[0] =nextAnimCompleteStr[0]; animCompleteStr[1] =nextAnimCompleteStr[1]; nextAnim =NULL; // Queue is cleared. nextFinishAnim =NULL; nextAnimCompleteStr[0] ='-'; nextAnimCompleteStr[1] ='-'; // Record the number of times to play the animation. animNumLoops =nextAnimNumLoops; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } //-------------------------------------------------------------------------------------- // If we are currently playing an animation, then update the animation state and the // servo positions. //-------------------------------------------------------------------------------------- if (animInProgress) { // Determine if we need to switch to the next frame. int timeInCurrFrame =currTime - timeAtStartOfFrame; if (timeInCurrFrame> currAnim[targetFrame][TWEEN_TIME_VALUE]) { // Set the servo positions to the targetFrame's values. // We only set this if the value is> 0. -ve values means that // the current target keyframe did not alter that servos position. if (currAnim[targetFrame][LEFT_HIP_VALUE]>=0) { currLeftHip =currAnim[targetFrame][LEFT_HIP_VALUE]; } if (currAnim[targetFrame][LEFT_FOOT_VALUE]>=0) { currLeftFoot =currAnim[targetFrame][LEFT_FOOT_VALUE]; } if (currAnim[targetFrame][RIGHT_HIP_VALUE]>=0) { currRightHip =currAnim[targetFrame][RIGHT_HIP_VALUE]; } if (currAnim[targetFrame][RIGHT_FOOT_VALUE]>=0) { currRightFoot =currAnim[targetFrame][RIGHT_FOOT_VALUE]; } UpdateServos(); // These current values are now the start of frame values. startLeftHip =currLeftHip; startLeftFoot =currLeftFoot; startRightHip =currRightHip; startRightFoot =currRightFoot; // Now, we try to move to the next frame. // - If there is a next frame, set that as the new target, and proceed. // - If there's no next frame, but it's looping, we re-add this animation // to the queue. // - If there's no next frame, and this is not looping, we stop animating. // (Remember that targetFrame is 1-based since the first element of the animation // data array is metadata) // Increment targetFrame, and reset time in the current frame. targetFrame++; timeAtStartOfFrame =currTime; // If there is no next frame, we stop this current animation. // If it is looping, then we re-queue the current animation if the queue is empty. if (targetFrame> NumOfFrames(currAnim)) { // Stop the current animation. animInProgress =false; // If we're looping forever, and there's no next anim, re-queue the // animation if the queue is empty. if ((animNumLoops <0) &&(nextAnim ==NULL)) { LoopAnim(currAnim, finishAnim, animCompleteStr); } // If we're looping forever, and there is something in the queue, then // finish the animation and proceed. else if ((animNumLoops <0) &&(nextAnim !=NULL)) { if (finishAnim !=NULL) { // Switch to the finish anim. currAnim =finishAnim; finishAnim =NULL; // Record the number of times to play the animation. animNumLoops =1; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } else { // We've stopped, so can notify if needed. // Print the command string we just finished. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(">"); } } // If we're looping a limited number of times, and there's no next anim, // re-queue the animation if the queue is empty. else if ((animNumLoops> 1) &&(nextAnim ==NULL)) { PlayAnimNumTimes(currAnim, finishAnim, animNumLoops-1, animCompleteStr); } // In this case, numAnimLoops is 1, this is the last loop through, so // we're done. We play the finishAnim first if needed. else { // If there is a finish animation, switch to that animation. if (finishAnim !=NULL) { // Switch to the finish anim. currAnim =finishAnim; finishAnim =NULL; // Record the number of times to play the animation. animNumLoops =1; // Treat current time as start of frame for the initial lerp to the first frame. timeAtStartOfFrame =currTime; // Set the frame counters. targetFrame =1; // First frame we are lerping to. Index 0 is metadata, so skip. // An animation is now in progress animInProgress =true; } // Otherwise, we're done! We've played the finishAnim if there was one. else { // Print the command string we just finished. softwareSerial.print("<"); softwareSerial.print(animCompleteStr); softwareSerial.println(">"); } } } } // If we're still animating (i.e. the previous check didn't find that // we've finished the current animation), then proceed. if (animInProgress) { // Set the servos per data in the current frame. We only update the servos that have target // microsecond values> 0. This is to support the feature where we leave a servo at its // existing position if an animation data item is -1. float frameTimeFraction =(currTime - timeAtStartOfFrame) / ((float) currAnim[targetFrame][TWEEN_TIME_VALUE]); if (currAnim[targetFrame][LEFT_HIP_VALUE]>=0) { currLeftHip =startLeftHip + ((currAnim[targetFrame][LEFT_HIP_VALUE] - startLeftHip) * frameTimeFraction); } if (currAnim[targetFrame][LEFT_FOOT_VALUE]>=0) { currLeftFoot =startLeftFoot + ((currAnim[targetFrame][LEFT_FOOT_VALUE] - startLeftFoot) * frameTimeFraction); } if (currAnim[targetFrame][RIGHT_HIP_VALUE]>=0) { currRightHip =startRightHip + ((currAnim[targetFrame][RIGHT_HIP_VALUE] - startRightHip) * frameTimeFraction); } if (currAnim[targetFrame][RIGHT_FOOT_VALUE]>=0) { currRightFoot =startRightFoot + ((currAnim[targetFrame][RIGHT_FOOT_VALUE] - startRightFoot) * frameTimeFraction); } UpdateServos(); } }}// Move all the servo to the positions set in the curr... variables.// In the code, we update those variables and then call this to set the servos.void UpdateServos(){ servoLeftHip.writeMicroseconds(currLeftHip); servoLeftFoot.writeMicroseconds(currLeftFoot); servoRightHip.writeMicroseconds(currRightHip); servoRightFoot.writeMicroseconds(currRightFoot);}// Return the number of frames in the given animation data.// Have this helper function to avoid the "magic number" reference of animData[0][0].int NumOfFrames(int animData[][5]){ return animData[0][0];}

Schema's


Productieproces

  1. Raspberry Pi-robot bestuurd via Bluetooth
  2. DIY LUMAZOID Arduino Music Visualiser
  3. Arduino digitale dobbelstenen
  4. DIY 37 LED Roulette Game
  5. DIY voltmeter met Arduino en smartphone
  6. Spraakgestuurde robot
  7. Arduino-gestuurde pianorobot:PiBot
  8. NeoMatrix Arduino Pong
  9. DIY Arduino-robotarm – bestuurd door handgebaren
  10. 4-wiel robot gemaakt met Arduino bestuurd met behulp van Dabble
  11. Boltgestuurde robotauto