Partagez

Suivez moi

Twitter

Google+

LinkedIn

MovingRaspi - Partie 02 : Communication iPhone -> Raspberry Pi

MovingRaspi est un projet que j'avais eu il y a quelques temps, et pour lequel j'ai décidé de me lancer. Il s'agit de motoriser un Raspberry Pi tout en le pilotant depuis un iPhone (ou iPad, ou iPod Touch). Cette deuxième partie concerne la communication entre l'iPhone et le Raspberry Pi.

 

Les bases techniques

Pour une question de facilité de programmation, le protocole de communication entre l'iPhone et le Raspberry Pi sera très simple. Les commandes seront envoyées de manière textuelle au Raspberry, et sont les suivantes :

  • forward : les deux roues du robot tournent de manière à faire avancer le robot, jusqu'à la réception de la commande « stop ».
  • reverse : les deux roues du robot tournent de manière à faire reculer le robot, jusqu'à la réception de la commande « stop ».
  • left : la roue gauche fait reculer le robot, la roue droite le fait avancer : le robot pivote vers la gauche, jusqu'à la réception de la commande « stop ».
  • right : la roue gauche fait avancer le robot, la roue droite le fait reculer : le robot pivote vers la droite, jusqu'à la réception de la commande « stop ».
  • stop : les deux roues arrêtent de tourner.

L'appui sur un bouton de l'iPhone envoie la commande de déplacement correspondante (pas d'envoi en boucle, juste un unique envoi), et le fait de relâcher le bouton envoie la commande « stop ». Le fait de laisser le doigt sur le bouton permet donc d'exécuter la commande choisie indéfiniment.

Côté Raspberry Pi

La partie serveur est basée sur la bibliothèque Twisted pour Python. Twisted fournit tout ce qu'il faut pour créer un serveur TCP facilement.

La base du serveur est la suivante :

# Protocole de gestion des commandes de MovingRaspiRemote
class MovingRaspi(Protocol):
  # Lors de la connexion d'un client
  def connectionMade(self):
    print("Un client s'est connecté")

  # Lors de la réception d'une commande
  def dataReceived(self, data):
    if data == "forward":
      # La roue gauche avance
      ... insérer le code correspondant ...
      # La roue droite avance
      ... insérer le code correspondant ...

    elif data == "reverse":
      # La roue gauche recule
      ... insérer le code correspondant ...
      # La roue droite recule
      ... insérer le code correspondant ...

    elif data == "left":
      # La roue gauche recule
      ... insérer le code correspondant ...
      # La roue droite avance
      ... insérer le code correspondant ...

    elif data == "right":
      # La roue gauche avance
      ... insérer le code correspondant ...
      # La roue droite recule
      ... insérer le code correspondant ...

    else:
      # Toutes les roues s'arrêtent
      ... insérer le code correspondant ...


# Initialise Twisted
factory = Factory()

# Assigne à Twisted le protocole de gestion des commandes
factory.protocol = MovingRaspi

# Indique au serveur qu'il doit écouter toutes les interfaces réseau, sur le port 8000
reactor.listenTCP(8000, factory, 50, '0.0.0.0')

# Démarre le serveur TCP, qui va attendre les connexions des clients
reactor.run()
          

Le code complet du serveur est disponible sur GitHub. Afin de le tester, il faut faire à minima le montage suivant :

Temporary assembly
Temporary schematics

Les LEDs 1 à 4 correspondent aux transistors commandant le moteur de droite, les LEDs 5 à 8 correspondent aux transistors commandant le moteur de gauche.

  • Pour la marche avant : LED 1, 2, 5 et 6 allumées.
  • Pour la marche arrière : LED 3, 4, 7 et 8 allumées.
  • Pour pivoter à droite : LED 3, 4, 5 et 6 allumées.
  • Pour pivoter à gauche : LED 1, 2, 7 et 8 allumées.

Les explications sur le fonctionnement des transistors seront données dans la troisième partie.

Côté iPhone

L'interface attendue pour l'application iPhone est la suivante :

MovingRaspi Remote

Le controleur de la vue doit implémenter le protocole « NSStreamDelegate » pour la gestion des communications avec le serveur.

Le bouton de connexion doit appeler la fonction suivante lors de l'évènement « TouchUpInside »

- (IBAction)doConnect:(id)sender {
    // Définit la connexion TCP à ouvrir avec le serveur
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)CFBridgingRetain(@"hostname"), [@"port" intValue], &readStream, &writeStream);
    _outputStream = (NSOutputStream *)CFBridgingRelease(writeStream);

    [_outputStream setDelegate:self];

    [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

    // Ouvre la connexion TCP avec le serveur
    [_outputStream open];
}          

Le bouton de déconnection doit appeler la fonction suivante lors de l'évènement « TouchUpInside »

- (IBAction)doDisconnect:(id)sender {
    // Ferme la connexion TCP avec le serveur

    [_outputStream close];
}
          

Le bouton « Forward » doit appeler la fonction suivante lors de l'évènement « TouchDown » (à adapter pour les boutons « Reverse », « Left » et « Right », en appelant les bonnes commandes).

- (IBAction)goForward:(id)sender {
    // Envoie la commande "forward" lors de l'appui sur le bouton Forward

    NSString *response  = @"forward";
    NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
    [_outputStream write:[data bytes] maxLength:[data length]];
}
          

Les boutons « Forward »,« Reverse », « Left » et « Right » doivent appeler la fonction suivante lors de l'évènement « TouchUpInside »

// Envoie la commande "stop" lors du relâchement du bouton

NSString *response  =  @"stop";
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[_outputStream write:[data bytes] maxLength:[data length]];          

Le code complet de MovingRaspiRemote est disponible sur GitHub. Afin de le tester, il faut l'installer sur votre iDevice (iPhone / iPad / iPod Touch). Si vous n'avez pas de compte développeur iOS Apple, le code est utilisable avec le simulateur iOS..

Au final

La totalité du code pour cette partie est disponible sur GitHub.

Une vidéo du fonctionnement est visible ci-dessous :



comments powered by Disqus