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.
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 :
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.
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 :
Les LEDs 1 à 4 correspondent aux transistors commandant le moteur de droite, les LEDs 5 à 8 correspondent aux transistors commandant le moteur de gauche.
Les explications sur le fonctionnement des transistors seront données dans la troisième partie.
L'interface attendue pour l'application iPhone est la suivante :
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..
La totalité du code pour cette partie est disponible sur GitHub.
Une vidéo du fonctionnement est visible ci-dessous :