Accéder au contenu principal

Hack du RoboSapien en Infra-Rouge

Mon fils a eu un RoboSapien V1 il y a une dizaine d'années. Il prenait la poussière sur le haut d'une armoire, jusqu'à ce que j'ai envie de le ramener à la vie. Il était temps, les piles étaient en train de commencer à couler et vu le nombre de servo moteurs qu'il contient, ses jours étaient comptés. Mais non, j'ai réussi à contenir mon irrésistible envie de tout démonter et j'ai décidé de passer par la télécommande Infrarouge pour le piloter.
Le protocole est assez similaire de celui d'une télécommande infrarouge classique avec cependant quelques petites différences. Il est correctement expliqué sur les sites http://www.aibohack.com/robosap/ir_codes.htm et http://www.markcra.com/robot/ir_codes.php. Je vais traduire en français pour ceux qui auraient un peu de difficulté. Il existe des librairies Arduino, mais comme d'habitude, pas toujours de librairie en C#.
Voici les choses importantes à connaitre sur le protocole :
  1. Le protocole envoie un code sur 8 bits précédé par une entête
  2. Les signaux sont envoyés sur la base 1/1200 secondes (0,833 ms)
  3. Le signal est normalement à 1 (HIGH) au début. Un signal envoyé pendant 65758 ns.
  4. L'entête est à 0 (DOWN) pendant 8*1/1200 = 8*833 ns = 6664 ns
  5. Les données sont envoyées sur 8 bits
    1. Pour la valeur 0, mettre le signal à HIGH pendant 0,833 ms et à DOWN pendant 0,833 ms
    2. Pour la valeur 1, mettre le signal à HIGH pendant 4*0,833 ms et à DOWN pendant 0,833 ms.
  6. A la fin, mettre le signal HIGH pendant 65758 ns.
___________          ____   _   _   _   _   ____   ____   _   ___
           |        |    | | | | | | | | | |    | |    | | | |    
           |        |    | | | | | | | | | |    | |    | | | |      
           |________|    |_| |_| |_| |_| |_|    |_|    |_| |_|     
  65758ns    6664ns   1     0   0   0   0    1      1     0    end


Voici la librairie en C#. Je me suis inspiré de la librairie de décodage des signaux IR de Sony et j'ai rajouté les commandes pour envoyer le signal.

 using System;  
 using Microsoft.SPOT;  
 using System.Threading;  
 using ITEADStudio;  
 using Microsoft.SPOT.Hardware;  
 using GHIElectronics.NETMF.FEZ;  
 using GHIElectronics.NETMF.Hardware;  
 namespace DemoIR  
 {  
   public class RoboSapienIR : IDisposable  
   {  
     static bool running = false;  
     static Thread thread;  
     // Infra Red  
     static OutputCompare remoteGenerator;  
     static PinCapture cap;  
     const int DataLength = 8;  
     private readonly long[] _pulsesDown;  
     private readonly long[] _pulsesUp;  
     const int StartSequence = 60000;  
     const int LogicalOne = 20000;  
     static int[] bits = new int[] { 128, 64, 32, 16, 8, 4, 2, 1 };  
     const int bit0 = 833; //757;  
     const int bitDown = 833; //952;  
     const int bit1 = 4 * bit0; //3366;  
     const int bitHeaderUp = 65758;  
     const int bitHeaderDown = 8 * bit0;  
     public enum Commands  
     {  
       // No Shift  
       TurnRight = 0x80, //$80 - turn right (on left side of remote)  
       RightArmUp = 0x81, //$81 - right arm up (upper left button on remote)  
       RightArmOut = 0x82, //$82 - right arm out  
       TiltBody = 0x83, //$83 - tilt body right  
       RightArmDown = 0x84, //$84 - right arm down  
       RighArmIn = 0x85, //$85 - right arm in  
       WalkForward = 0x86, //$86 - walk forward  
       WalkBackward = 0x87, //$87 - walk backward  
       TurnLeft = 0x88, //$88 - turn left (on right side of remote)  
       LeftArmUp = 0x89, //$89 - left arm up (upper right button on remote)  
       LeftArmOut = 0x8A, //$8A - left arm out  
       TiltBodyLeft = 0x8B, //$8B - tilt body left  
       LeftArmDown = 0x8C, //$8C - left arm down  
       LeftArmIn = 0x8D, //$8D - left arm in  
       Stop = 0x8E, //$8E - stop  
       // Green Shift commands  
       RightTurnStep = 0xA0, //$A0 - right turn step  
       RightHandThump = 0xA1, //$A1 - right hand thump  
       RightHandThrow = 0xA2, //$A2 - right hand throw  
       Sleep = 0xA3, //$A3 - sleep  
       RightHandPickUp = 0xA4, //$A4 - right hand pickup  
       LeanBackward = 0xA5, //$A5 - lean backward  
       ForwardStep = 0xA6, //$A6 - forward step  
       BackwardStep = 0xA7, //$A7 - backward step  
       LeftTurnStep = 0xA8, //$A8 - left turn step  
       LeftHandThump = 0xA9, //$A9 - left hand thump  
       LeftHandThrow = 0xAA, //$AA - left hand throw  
       Listen = 0xAB, //$AB - listen  
       LeftHandPickup = 0xAC, //$AC - left hand pickup  
       LeanForward = 0xAD, //$AD - lean forward  
       Reset = 0xAE, //$AE - reset  
       ExecuteMaster = 0xB0,//$B0 - Execute (master command program execute)  
       Wakeup = 0xB1, //$B1 - Wakeup  
       Right = 0xB2, //$B2 - Right (right sensor program execute)  
       Left = 0xB3, //$B3 - Left (left sensor program execute)  
       Sonic = 0xB4, //$B4 - Sonic (sonic sensor program execute)   
       // Orange shift commands        
       RightHandStrike3 = 0xC0,//$C0 - right hand strike 3  
       RightHandSweep = 0xC1, //$C1 - right hand sweep  
       Burp = 0xC2, //$C2 - burp  
       RightHandStrike2 = 0xC3, //$C3 - right hand strike 2  
       High5 = 0xC4, //$C4 - high 5  
       RightHandStrike1 = 0xC5,//$C5 - right hand strike 1  
       Bulldozer = 0xC6, //$C6 - bulldozer  
       Oops = 0xC7, //$C7 - oops (fart)  
       LeftHandStrike3 = 0xC8, //$C8 - left hand strike 3  
       LeftHandSweep = 0xC9, //$C9 - left hand sweep  
       Whistle = 0xCA, //$CA - whistle  
       LeftHandStrike2 = 0xCB, //$CB - left hand strike 2  
       Talkback = 0xCC, //$CC - talkback  
       LeftHandStrike1 = 0xCD, //$CD - left hand strike 1  
       Roar = 0xCE, //$CE - roar  
       AllDemo = 0xD0, //$D0 - All Demo  
       PowerOff = 0xD1, //$D1 - Power Off (drop snow-globe and say "Rosebud")  
       Demo1 = 0xD2, //$D2 - Demo 1 (Karate skits)  
       Demo2 = 0xD3, //$D3 - Demo 2 (Rude skits)  
       Dance = 0xD4 //$D4 - Dance   
     }  
     public RoboSapienIR(Cpu.Pin inputPin, Cpu.Pin outputPin)  
     {  
       cap = new PinCapture(inputPin, Port.ResistorMode.Disabled);  
       remoteGenerator = new OutputCompare(outputPin, false, 300);  
       _pulsesDown = new long[DataLength];  
       _pulsesUp = new long[DataLength];  
     }  
     /// <summary>  
     /// Blocking method for input pulse measuring  
     /// </summary>  
     /// <param name="port">Input port</param>  
     /// <param name="state">State to measure length</param>  
     /// <returns>Pulse length in ticks</returns>  
     private static long PulseIn(PinCapture port, bool state, out long up, out long down)  
     {  
       var lowTime = DateTime.Now;  
       while (port.InternalPort.Read() != state) { }  
       var startTime = DateTime.Now;  
       while (port.InternalPort.Read() == state) { }  
       var delta = DateTime.Now - startTime;  
       up = startTime.Ticks - lowTime.Ticks;  
       down = delta.Ticks;  
       return up;  
     }  
     public int ReadSignal()  
     {  
       Debug.Print("Capturing...");  
       long headerUp;  
       long headerDown;  
       // wait for start sequence  
       while ((headerUp = PulseIn(cap, false, out headerUp, out headerDown)) < StartSequence) { }  
       // receive data  
       for (int i = 0; i < DataLength; i++)  
       {  
         PulseIn(cap, false, out _pulsesUp[i], out _pulsesDown[i]);  
       }  
       Debug.Print("Head #0" + "= " + headerUp);  
       Debug.Print("Head #1" + "= " + headerDown);  
       for (int i = 0; i < _pulsesDown.Length; i++)  
       {  
         Debug.Print("Edge #" + i + "= " + _pulsesUp[i]);  
         Debug.Print("Down #" + i + "= " + _pulsesDown[i]);  
       }  
       Debug.Print("Done programing!");  
       int command = -1;  
       DecodePulses(_pulsesUp, out command);  
       Debug.Print("Command = " + command);  
       return command;  
     }  
     /// <summary>  
     /// Decodes received pulses using SONY protocl  
     /// </summary>  
     /// <param name="pulses">Array with pulses</param>  
     /// <param name="command">Command decoded</param>  
     public static void DecodePulses(long[] pulses, out int command)  
     {  
       command = 0;  
       byte mask;  
       // Decode command  
       for (int i = 0; i < pulses.Length; i++)  
       {  
         mask = (pulses[i] > LogicalOne) ? (byte)1 : (byte)0;  
         //mask <<= i;  
         //command |= mask;  
         command += mask * bits[i];  
       }  
     }  
     public void RSPlay(Commands command)  
     {  
       RSPlay((uint)command);  
     }  
     public void RSPlay(uint command)  
     {  
       Debug.Print("Send RS signal " + command);  
       uint[] rsbuffer = new uint[19];  
       rsbuffer[0] = bitHeaderUp;  
       rsbuffer[1] = bitHeaderDown;  
       for (int i = 1; i < 9; i++)  
       {  
         if ((command & 128) != 0)  
           rsbuffer[i * 2] = bit1;  
         else  
           rsbuffer[i * 2] = bit0;  
         command <<= 1;  
         rsbuffer[i * 2 + 1] = bitDown;  
       }  
       rsbuffer[18] = bitHeaderUp;  
       remoteGenerator.SetBlocking(false, rsbuffer, 0, rsbuffer.Length, 100, true, 38000);  
     }
     public void Dispose()  
     {  
       sensor = null;  
       stop();  
     }  
     public void stop()  
     {  
       running = false;  
     }  
     public string ToString(long command) {  
       switch (command)  
       {  
         case 0x80 : return "Turn right (on left side of remote)";  
         case 0x81 : return "Right arm up (upper left button on remote)";  
         case 0x82 : return "Right arm out";  
         case 0x83 : return "Tilt body right";  
         case 0x84 : return "Right arm down";  
         case 0x85 : return "Right arm in";  
         case 0x86 : return "Walk forward";  
         case 0x87 : return "Walk backward";  
         case 0x88 : return "Turn left (on right side of remote)";  
         case 0x89 : return "Left arm up (upper right button on remote)";  
         case 0x8A : return "Left arm out";  
         case 0x8B : return "Tilt body left";  
         case 0x8C : return "Left arm down";  
         case 0x8D : return "Left arm in";  
         case 0x8E : return "Stop";  
         case 0x90 : return "P (Master Command Program)";  
         case 0x91 : return "P>> (Program Play, the one on the bottom)";  
         case 0x92 : return "R>> (Right sensor program)";  
         case 0x93 : return "L>> (Left sensor program)";  
         case 0x94 : return "S>> (Sonic sensor program)";  
         case 0xA0 : return "Right turn step";  
         case 0xA1 : return "Right hand thump";  
         case 0xA2 : return "Right hand throw";  
         case 0xA3 : return "Sleep";  
         case 0xA4 : return "Right hand pickup";  
         case 0xA5 : return "Lean backward";  
         case 0xA6 : return "Forward step";  
         case 0xA7 : return "Backward step";  
         case 0xA8 : return "Left turn step";  
         case 0xA9 : return "Left hand thump";  
         case 0xAA : return "Left hand throw";  
         case 0xAB : return "Listen";  
         case 0xAC : return "Left hand pickup";  
         case 0xAD : return "Lean forward";  
         case 0xAE : return "Reset";  
         case 0xB0 : return "Execute (master command program execute)";  
         case 0xB1 : return "Wakeup";  
         case 0xB2 : return "Right (right sensor program execute)";  
         case 0xB3 : return "Left (left sensor program execute)";  
         case 0xB4 : return "Sonic (sonic sensor program execute)";  
         case 0xC0 : return "Right hand strike 3";  
         case 0xC1 : return "Right hand sweep";  
         case 0xC2 : return "Burp";  
         case 0xC3 : return "Right hand strike 2";  
         case 0xC4 : return "High 5";  
         case 0xC5 : return "Right hand strike 1";  
         case 0xC6 : return "Bulldozer";  
         case 0xC7 : return "Oops (fart)";  
         case 0xC8 : return "Left hand strike 3";  
         case 0xC9 : return "Left hand sweep";  
         case 0xCA : return "Whistle";  
         case 0xCB : return "Left hand strike 2";  
         case 0xCC : return "Talkback";  
         case 0xCD : return "Left hand strike 1";  
         case 0xCE : return "Roar";  
         case 0xD0 : return "All Demo";  
         case 0xD1 : return "Power Off (drop snow-globe and say \"Rosebud\")";  
         case 0xD2 : return "Demo 1 (Karate skits)";  
         case 0xD3 : return "Demo 2 (Rude skits)";  
         case 0xD4: return "Dance";  
         default: return "Command not found";  
       }  
     }  
   }  
 }  


Commentaires

  1. Hello,
    Comment faire pour connecter le robosapien v1 au PC ?

    RépondreSupprimer
    Réponses
    1. Bonjour Diprog59,

      Solution 1 - Connexion Infra Rouge (IR) non intrusive
      Il y a une dizaine d'année, la plupart des laptops étaient équipés d'une interface Infra Rouge. Sur un PC fixe, il était également possible de s'équiper d'un dongle Infrarouge (voir l'ActiSYS 220 que j'ai acheté à l'époque). Cette interface supportait essentiellement le protocol série IRDA, mais il était possible en "grugeant" un peu de simuler un protocol IR de télécommande en envoyant des caractères. Il fallait cependant jouer sur les bits d'arrêts, la vitesse de transmission, etc.
      Aujourd’hui, il existe des extensions PC telles que le PCIR (http://www.intolect.com/pcirdetail.htm) ou l'USB-UIRT (http://www.usbuirt.com/order.htm) qui permettent à la fois de recevoir et d'émettre. Leur prix varie entre 35 et 50€.
      Personnellement, j'utiliserai plutôt un micro-contrôleur tel que le Fez-Panda II ou le FEZ Cerbuino Bee avec une interface Bluetooth ou une interface Ethernet (pour le Cerbuino Bee). Le PC aurait ainsi juste à transmettre en Bluetooth ou via ethernet le code à envoyer en IR par le micro-contrôleur. J'essaierai de poster le dispositif correspondant la semaine prochaine.

      Solution 2 - Ouvrir le Robosapiens pour le contrôler directement à partir d'un micro-contrôleur
      Certains de mes collègues de Bell Labs l'ont fait pour les besoins d'une démo il y a 4 ans environ. Ils ont collé un Arduino au dos d'un RS et piloté le tout à partir d'un PC connecté à une XBOX Kinect. Le robot avait un long fil à la patte, mais le résultat était bluffant. Cela demande un peu plus d'expertise et d'avoir le courage de démonter son Robosapiens. Tu pourras trouver des exemples sur http://playground.arduino.cc/Main/RoboSapienIR et http://www.markcra.com/robot/hackrobos.php, mais c'est vraiment très intrusif. L'approche IR me semble beaucoup plus douce.

      ftoure

      Supprimer

Enregistrer un commentaire

Posts les plus consultés de ce blog

Supprimer les partitions Raspberry sur une carte SD sous Windows 7 avec Diskpart

Si vous souhaitez récupérer une ancienne carte SD utilisée pour démarrer un Raspberry pour un autre usage (appareil photo, etc), il vous faudra supprimer les deux partitions créées au moment de l'écriture de l'image sur la carte SD. Vous pouvez voir les partition en sélectionnant Menu Windows/Ordinateur/bouton droit "Gérer". Voici un exemple du résultat final. Vous pouvez supprimer la partition Unix de 7 Gb (ou 4Gb en fonction de la taille de votre carte) en sélectionnant la partition puis en faisant "bouton droit Supprimer". Laissez juste une partition pour pouvoir faire les autres manipulations avec DISKPART. Démarrez l'outil DISKPART en ligne de commande. Une nouvelle fenêtre s'ouvrira. Microsoft DiskPart version 6.1.7601 Copyright (C) 1999-2008 Microsoft Corporation. Sur l'ordinateur : FRVILN0H305806 DISKPART> list disk   N° disque  Statut         Taille   Libre    Dyn  GPT   ---------  -------------  -------  -------  ---  ---   D

Comment lire son écran de téléphone Android sur PC (2)

Voici une nouvelle manière d'accéder à votre téléphone depuis votre PC. Cette méthode utilise le câble USB et Google Chrome. Elle fonctionne donc sur Windows, Mac et Linux. Les pré-requis sont les mêmes que ceux du billet précédent : Téléphone configuré en mode Développement Drivers USB installés sur le PC Google Chrome installé L'application Vysor s'installe comme une extension de Google Chrome. Cherchez dans le Webstore et lancez l'installation. Une fois installée, l'application apparaît dans les extensions. Vous pouvez la lancer de différentes manières. La manière la plus simple est d'ouvrir la fenêtre des applications : chrome://apps/ Une autre manière est de créer un raccourci en cliquant sur « Détails ». Ensuite créez un raccourci sur le bureau, le menu démarrer et/ou la barre de tâche. Vous pouvez également cliquer sur afficher dans la boutique et lancer l'application depuis la boutique. Une fois

Serveur d'impression CUPS sur Raspberry Pi

Je possède une très vieille imprimante laser HP Laserjet 6L noir et blanc de 12 ans d'age qui a survécu à plusieurs imprimantes jet d'encre couleurs tombées en désuétude pour obsolescence programmée. J'envisage tout de même sérieusement de les démanteler pour les recycler en CNC, graveur ou autre.   Je continue donc a utiliser cette bonne petite imprimante parallèle qui me rend bien des services (en 12 ans, j'ai changé le toner 3 fois pour un coût de 20 € la cartouche). J'ai donc dû m'équiper d'une adaptateur USB/Parallèle pour pouvoir la connecter sur un PC récent. Le problème principal est que le driver de cette imprimate n'est reconnu que par un seul de mes PC sous Windows 7. Les autres PC sous Windows 8 ou Windows 10 reconnaissent bien l'imprimante, mais sortent des feuilles avec le code Postscript. L'impression depuis une tablette ou un téléphone Androïd est également tout simplement impossible. Pour remédier à ce problème, j'ai don