Dans cet article, nous allons voir comment piloter un robot Lego PoweredUp à l’aide d’un JoyPad, grâce à un Raspberry Pi. Nous allons installer tout le nécessaire sur notre Raspberry Pi pour pouvoir piloter notre modèle Lego PoweredUp. Nous utiliserons NodeJS, donc le langage JavaScript, pour piloter notre modèle Lego.
Dans l’article « Contrôler vos modèles Lego au joypad à l'aide de BrickPi » de Hackable n°29, nous avons vu comment piloter des moteurs Lego Mindstorms à l’aide de la carte d’extension BrickPi. Nous allons maintenant faire de même, en replaçant BrickPi par le Hub Lego PoweredUp. Il existe une librairie NodeJS pour piloter ce hub, c’est pour cela que nous allons développer notre programme en JavaScript. Le principe et le fonctionnement du programme sont les mêmes que dans l’article précédent, seule l’implémentation change.
1. PoweredUp Lego
Lego propose depuis peu des moteurs et senseurs pilotables par Bluetooth. Toute l’intelligence est donc déportée sur la tablette ou le téléphone mobile. Le composant central est appelé hub. Ce composant est à la fois le boîtier contenant les piles, ainsi que le récepteur Bluetooth 4.1.
Le but de cet article est donc de remplacer l’application Lego PoweredUp [1] par du code JavaScript, que nous exécuterons sur RaspBerry Pi.
2. Le matériel
La liste du matériel est assez simple, car Lego nous propose déjà un modèle contenant pratiquement tout ce qui nous intéresse :
- 1 Raspberry Pi supportant le Bluetooth 4.1. Dans notre exemple, nous utiliserons un RaspBerry Pi 3 A+.
- 1 carte SD ou micro SD, en fonction du modèle de RaspBerry Pi choisi.
- 1 Lego «La Batmobile télécommandée» modèle 76112. Ce modèle fonctionne avec Lego PoweredUp.[2]
- 1 JoyPad reconnu sous Linux. Ici, nous utiliserons un Logitech F710.
- 6 piles AAA, de préférence rechargeables, pour alimenter le Hub Lego PoweredUp.
3. Construction du robot Lego
Lego propose un modèle contenant tout ce qui nous intéresse, il s’agit de « La Batmobile télécommandée » modèle numéro 76112. On trouve la notice de montage sur le site Lego : https://www.lego.com/fr-fr/service/buildinginstructions/search#?search&text=76112
Vous trouverez ce modèle sur le site MecaBricks : https://mecabricks.com/en/models/WRaZLqdAjpZ
4. Configuration logicielle
Nous supposerons ici que nous disposons d’un système Raspbian opérationnel. Par exemple, la version 2018-11-13-raspbian-stretch-lite.img.
Ensuite, nous avons besoin d’installer quelques packages pour la suite :
sudo aptitude install git npm
sudo npm install gamepad
Installons la librairie prenant en charge PoweredUp [3] :
sudo npm install node-poweredup --save
5. Principe et fonctionnement
Le but du programme que nous allons écrire est très simple: pouvoir piloter notre robot à l’aide d’un Joypad.
Nous allons développer notre programme en NodeJS. Il nous faut donc 2 bibliothèques :
- gamepad : pour nous permettre de récupérer les événements sur le JoyPad ;
- node-poweredup : pour nous permettre de piloter les 2 moteurs de notre robot Lego.
Nous allons piloter le moteur gauche du robot par la gâchette gauche du JoyPad et le moteur droit par la gâchette droite.
Les valeurs de la pression sur la gâchette se situent dans l’intervalle -1,00 à +1,00.
Les valeurs d’entrée du moteur se situent entre -100 et +100, avec un moteur à l’arrêt à 0.
Nous allons donc devoir convertir les valeurs d’entrée récupérées du JoyPad pour obtenir les bonnes valeurs de sortie à transmettre aux moteurs.
Nous devons prendre en suite en considération 2 paramètres :
- la valeur minimale du moteur pour que celui-ci fasse avancer le robot (variable vitesse_min) ;
- les valeurs de vitesse que l’on veut transmettre au robot. Dans l’absolu, nous pourrions tout transmettre, mais le temps de prise en compte de la vitesse par la librairie PoweredUp induit de la latence, donc un robot qui obéit avec un temps de retard. Nous définissons donc ici un seuil au-dessus duquel nous propagerons les ordres (variable seuil_detection).
Vous pouvez visualiser tout ceci sur le schéma.
6. Programmation
1 const GAMEPAD_EVENEMENTS_MS = 100;
2 const BOUTON_FIN = 7;
3 const BOUTON_AV_AR = 0;
4 const AXES = [2,5];
5
6 const gamepad = require("gamepad");
7
8 var robot =
9 {
10 "type":"PoweredUP",
11 "pret":false,
12 "connexion":null,
13 "moteurs":
14 [
15 {
16 "description":"Moteur gauche",
17 "nom":"B",
18 "vitesse":0,
19 "sens":-1
20 },
21 {
22 "description":"Moteur droite",
23 "nom":"A",
24 "vitesse":0,
25 "sens": 1
26 }
27 ],
28 "vitesse_min": 40,
29 "seuil_detection":40
30 }
31
32 robot.init = function() {
33 const PoweredUP = require("node-poweredup");
34 const poweredUP = new PoweredUP.PoweredUP();
35 poweredUP.on("discover", async (hub) => {
36 await hub.connect();
37 robot.connexion = hub;
38 robot.pret = true;
39 console.log("Lego PoweredUP OK");
40 });
41 poweredUP.scan();
42 }
43
44 robot.modifie_vitesse = function(moteur,vitesse) {
45 robot.moteurs[moteur].vitesse=robot.moteurs[moteur].sens*vitesse;
46 robot.connexion.setMotorSpeed(
47 robot.moteurs[moteur].nom,
48 robot.moteurs[moteur].vitesse)
49 }
50
51 robot.init();
52 gamepad.init();
53 setInterval(gamepad.processEvents, GAMEPAD_EVENEMENTS_MS);
54 console.log("GamePad OK")
55
56 gamepad.on("down", function (id, num) {
57 if (num == BOUTON_FIN) return process.exit(0);
58 if (num == BOUTON_AV_AR)
59 {
60 if ((robot.moteurs[0].vitesse==0) &&
61 (robot.moteurs[1].vitesse==0))
62 {
63 robot.moteurs[0].sens = -1 * robot.moteurs[0].sens;
64 robot.moteurs[1].sens = -1 * robot.moteurs[1].sens;
65 }
66 }
67 });
68
69 gamepad.on("move", function (id, axis, value) {
70 if (!robot.pret) return;
71 vitesse=Math.round((value+1)*50);
72
73 if (vitesse < robot.vitesse_min) vitesse=0;
74
75 for (i = 0; i < AXES.length; i++)
76 if (axis==AXES[i])
77 if (Math.abs(robot.moteurs[i].vitesse - vitesse) > robot.seuil_detection)
78 robot.modifie_vitesse(i,vitesse);
79 });
Voici une description du fonctionnement de notre programme.
Tout d’abord, quelques constantes (lignes 1 à 4) :
- GAMEPAD_EVENEMENTS_MS : période de rafraîchissement de données du GamePad ;
- BOUTON_FIN : identifiant du bouton mettant fin au programme ;
- BOUTON_AV_AR : identifiant du bouton permettant la bascule marche avant / marche arrière ;
- AXES : tableau contenant les 2 axes du JoyPad, à utiliser pour le moteur gauche et le moteur droit.
En ligne 6, nous chargeons la librairie d’utilisation du GamePad.
Des lignes 8 à 30, nous définissons les caractéristiques du robot.
Une des grandes forces de JavaScript est que nous pouvons dynamiquement ajouter une fonction à un objet. C’est ce que nous faisons des lignes 32 à 42 avec la fonction init, ainsi que des lignes 44 à 49 avec la fonction modifie_vitesse.
La fonction init du robot permet la connexion Bluetooth et l’initialisation du Hub Lego.
La fonction modifie_vitesse prend 2 arguments, le moteur dont on veut changer la vitesse et la nouvelle vitesse.
Des lignes 51 à 54, nous démarrons le programme en initialisant le JoyPad et le robot.
Il ne nous reste donc plus qu’à réagir sur les actions du JoyPad.
Des lignes 56 à 67, nous détectons si on appuie sur un bouton du JoyPad :
- s’il s’agit du bouton de fin, nous arrêtons le programme (ligne 57) ;
- s’il s’agit du bouton marche avant / marche arrière, nous vérifions d’abord que le robot est bien arrêté (vitesse == 0) et ensuite, nous changeons le sens de rotation des 2 moteurs (lignes 60 à 65).
Des lignes 69 à 79, nous détectons la pression sur les gâchettes du JoyPad. Tout d’abord, nous testons si le robot est prêt (ligne 70). Ensuite, nous calculons la nouvelle vitesse et nous vérifions si la vitesse minimale est atteinte (lignes 71 et 73). Pour finir, nous vérifions quelle gâchette est pressée (ligne 76) et nous modifions la vitesse du moteur uniquement s’il y a un écart de vitesse significatif (seuil_detection) avec la vitesse précédente (lignes 77 et 78).
Conclusion
Nous pouvons désormais piloter facilement au JoyPad notre Lego PowerUp. Avec ces bases, les possibilités de développement sont infinies… À vous de créer vos modèles et programmes et de les partager avec la communauté.
Il existe aussi une boîte de Lego appelée Lego Boost. Le fonctionnement est exactement le même à une exception : le hub intègre 2 moteurs et 2 ports. Ces ports permettent d’ajouter un moteur supplémentaire ainsi qu’un détecteur de couleur.
Lors de la création de cet article, il n’y avait malheureusement pas de librairie Python disponible. Ce qui n’est plus le cas [4] [5]. Le Raspberry Magazine numéro 81 (en anglais) aborde lui aussi le sujet Lego Boost piloté par Raspberry Pi. [6]
Références
[1] PoweredUp sur le site Lego : https://www.lego.com/en-us/service/device-guide/powered-up
[2] La Batmobile télécommandée sur le site Lego : https://www.lego.com/en-us/themes/dc-superheroes/products/app-controlled-batmobile-76112
[3] La librairie node-poweredup : https://www.npmjs.com/package/node-poweredup
[4] Une librairie Python pour Lego Boost : https://github.com/undera/pylgbst
[5] Une autre librairie Python pour Lego Boost : https://github.com/JorgePe/pyb00st
[6] Raspberry Magazine 81 en anglais : https://www.raspberrypi.org/magpi-issues/MagPi81.pdf