Vous souhaitez en savoir plus sur LivePose, le logiciel de détection de poses développé au Metalab ? Vous êtes à la recherche d’exemples d’utilisation afin de vous donner quelques idées ? En voici une !
Dans Ballant, nous allons créer ensemble un petit jeu basé sur les mouvements des bras. Le nom vient de l’expression « les bras ballants ».

Le programme est constitué des éléments suivants:
-
une page HTML
-
un fichier CSS
-
du code JavaScript
-
une instance de LivePose
Vous devez disposer d’une version égale ou supérieure à 0.11.0 de LivePose.
En commençant par la fin
Vous pouvez dès maintenant consulter une version complète de Ballant pour tester cet exemple.
Suite à l”installation de LivePose, déplacez-vous dans le dossier examples/ballant:
cd examples/ballant
Installez avec :
npm install
Lancez le jeu :
./ballant.sh
Des fenêtres de terminal et une fenêtre de navigateur web apparaîtront, en plus de la fenêtre de LivePose. Sélectionnez la fenêtre de navigation web: des instructions dénotant des mouvements de bras s’afficheront sur la page.
Balancez les bras vers le haut ou vers le bas pour jouer à Ballant. Vos succès s’afficheront à l’écran !
Comment fonctionne Ballant ?
En bref, le code JavaScript permet de reçevoir et traiter les messages OSC envoyés par LivePose. Ce code vérifie que la position des bras détectée par LivePose correspond ou non à celle demandée par Ballant. Enfin, le code est responsable de communiquer avec la personne jouant à Ballant par le biais de la page web.
Pour en savoir plus, continuez à lire : nous allons détailler chacune des étapes nécessaires à la réalisation de Ballant afin de vous servir de source d’inspiration pour vos propres projets.
Aperçu
Voici un diagramme donnant un aperçu du projet. Une description de celui-ci le suit.

Sur le diagramme, nous avons les noeuds et connexions suivants :
-
LivePose a le port 3334;
-
le noeud LivePose peut communiquer avec le serveur OSC sur le bord 9000;
-
le serveur OSC communique avec le client socket.io;
-
le client socket.io envoie les informations à la page web ballant.html;
-
la page web ballant.html communique avec le serveur socket.io sur le port 8081;
-
le serveur socket.io communique avec le client OSC;
-
et enfin, le client OSC se connecte avec LivePose sur le port 3334.
Ce diagramme est inspiré par celui se trouvant sur la bibliothèque JavaScript “osc-web”, utilisée par notre projet.
Commençons par la page web
La page web se nomme ballant.html. Regardons son contenu afin de souligner les parties essentielles à son fonctionnement.
En-tête <head>
Dans l’en-tête, nous retrouvons deux tags <script> et un tag <link>:
<script src="ballant.js" defer></script>
<script src="http://127.0.0.1:8081/socket.io/socket.io.js"></script>
<link href="style.css" rel="stylesheet">
Le premier tag permet de faire le lien avec le code JavaScript de Ballant, soit le fichier ballant.js.
Le second tag permet de créer une connexion WebSocket pour les messages OSC, à l’adresse 127.0.0.01:8081. La partie 127.0.0.1 de l’adresse correspond au localhost, soit l’adresse locale de votre ordinateur; la partie 8081 correspond au port utilisé pour la communication.
Quant au dernier tag, il permet d’utiliser la mise-en-page définie par style.css sur notre page web.
Les informations contenues dans ces trois tags définissent ainsi les moyens de communication disponibles pour la page web, le code qui pourra être exécuté et l’apparence de cette page web.
Communication humain-machine
Dans la section <body> de la page web, nous retrouvons différents tags <div>, nécessaires à la mise en page. Nous avons deux tags <p>, pour paragraphe, qui ont des id associées
<div class="info">
<p>It's time to ...</p>
<p id="action">... get ready!</p>
</div>
<div class="info">
<p id="congrats">Try again.</p>
</div>
Le tag <p> ayant action comme id nous permet de communiquer à l’humain le mouvement des bras exigé par Ballant.
Le tag <p> ayant congrats comme id nous permet de transmettre à l’humain l’état de succès ou d’échec quant au mouvement exigé.
Animons la page web avec LivePose
Nous allons utiliser du code JavaScript pour créer la logique du jeu Ballant.
Avant tout, configurons LivePose.
Configuration de LivePose
Le fichier default.json contient la configuration de LivePose pour Ballant.
Pour effectuer la connexion avec le script ballant.js, nous devons définir un port de connexion :
"outputs": {
"osc": {
"destinations": {
"localhost": 9000
}
}
Notez le chiffre utilisé, 9000. Nous allons le retrouver à la prochaine étape.
Connexion entre notre page web et LivePose
Construisons le pont entre LivePose et notre page web par le biais du script ballant.js.
Commençons par créer une connexion entre la page web et le script ballant.js :
var socket = io('http://127.0.0.1:8081');
Ici, nous utilisons le même port que celui de l’en-tête de la page web.
Créons la connexion entre le script ballant.js et LivePose :
socket.on('connect', function() {
socket.emit('config',
{
server: {
port: 9000,
host: 'localhost'
},
client: {
port: 3334,
host: '127.0.0.1'
}
});
});
Le port 9000 est le même que celui de la configuration de LivePose.
Le port 3334 permet à LivePose d’écouter les messages envoyés par notre page web.
Interprétation des messages reçus
La connexion entre les composantes de Ballant étant faite, nous pouvons passer au traitement des messages reçus par le script ballant.js provenant de LivePose.
Nous reçevons les messages dans la fonction socket.on:
socket.on('message', function(obj) {
// code ...
}
Tout le code se trouvant à l’intérieur de cette fonction a trait au traitement des messages.
La première instruction if nous permet de garder en mémoire les informations reçues dans le message. Nous nous intéressons au filtre “armup”.
if (obj[0].includes("armup")) {
var current_arm = obj[0];
var current_status = obj[1];
if (current_status == 1){
if (current_arm.includes('left')){
armleft_up = 1;
} else if (current_arm.includes('right')){
armright_up = 1;
}
}
Nous pouvons maintenant interpréter les messages reçus. Notons que la variable “required_pose” contient l’information sur la pose présentement demandée par le jeu Ballant.
if (required_pose == possible_poses[0]){
if ( armleft_up == 1 && armright_up == 0 ){
sayCongrats();
}
} else if (required_pose == possible_poses[1]){
if ( armright_up == 1 && armleft_up == 0){
sayCongrats();
}
} else if (required_pose == possible_poses[2]){
if ( armright_up == 1 || armleft_up == 1){
sayTryAgain();
} else {
sayCongrats();
}
}
Nous allons voir le contenu des fonctions sayCongrats() et sayTryAgain() dans la section suivante.
Boucle de jeu
La boucle de jeu est contenue dans la fonction changePose. Cette boucle est responsable de la génération d’une nouvelle pose, de son affichage sur la page web et de l’affichage du résultat (succès ou échec) obtenu par la personne jouant à Ballant. Cette fonction est appelée à chaque 3 secondes par setInterval.
- Génération d’une nouvelle pose
Nous générons une nouvelle pose en pigeant au hasard parmi la liste possible_poses des poses possibles, tel que décrit dans la fonction getPose :
function getPose(pose){
return possible_poses[getRandomInt(possible_poses.length)];
};
La fonction getRandomInt(m) permet d’obtenir un nombre entier inférieur à m. Ici, m prend comme valeur le nombre de choix possibles pour la pose, soit la longueur de la liste les contenant
- Affichage de la pose
Pour afficher la pose, regardons la fonction changePose() :
function changePose(){
document.getElementById("congrats").innerHTML = "Try again.";
required_pose = getPose(possible_poses);
armleft_up = 0;
armright_up = 0;
document.getElementById("action").innerHTML = required_pose;
}
La personne jouant à Ballant peut prendre connaissance de la nouvelle position demandée par le jeu.
- Affichage du résultat
Nous voulons maintenant communiquer le résultat des actions entreprises pour réaliser la position demandée par le jeu par la personne y jouant. Ceci est effectué par deux fonctions similaires, soit sayCongrats() et sayTryAgain() :
function sayCongrats(){
document.getElementById("congrats").innerHTML = "Congratulations!";
}
Lorsque la personne réussit la pose demandée, le message « Bravo ! » est affiché sur la page web, à l’endroit où se trouve le paragraphe ayant congrats comme id.
De même, lors la personne échoue la pose demandée, nous appelons la fonction sayTryAgain() :
function sayTryAgain(){
document.getElementById("congrats").innerHTML =
"You have lift at least one arm. Please try again.";
}
Cette fonction affiche un message visant à encourager un nouvel essai, dans le même paragraphe ayant congrats comme id.
Un script pour exécuter le tout
Pour pouvoir jouer à Ballant, nous avons besoin que ses différentes composantes soient actives.
Nous encapsulons les instructions nécessaires dans un script, nommé ballant.sh :
gnome-terminal -- npm run start
gnome-terminal -- sensible-browser index.html
cd ../../
gnome-terminal -- ./livepose.sh -c examples/ballant/default.json
cd examples/ballant/
Il est aussi possible d’exécuter ces trois étapes de façon indépendante, par la ligne de commande.
Et voilà !
Le tour détaillé des étapes entourant la création de Ballant est complété.
Si vous avez besoin d’un coup de main ou d’informations supplémentaires, voici les options possibles en ce moment :
-
ouvrir un commentaire dans une *issue* sur GitLab;
-
participer au Bureau ouvert du Metalab
Pour en savoir plus
Pour tous les détails, consultez la MR 173 sur GitLab.