Comment utiliser ROSlibjs avec ROS2 – French ROS2 Tutorial

07/05/2024

This tutorial is created by Robotics Ambassador 023 Enzo

Rosbotics Ambassador Program https://www.theconstruct.ai/rosbotics-ambassador/
Cours: ROS2 Basics in 5 Days C++: https://app.theconstructsim.com/courses/133

Dans ce tutoriel, nous allons voir comment utiliser ROSLibjs avec ROS2 pour tirer parti de la puissance de ROS dans des applications web et JavaScript. Nous allons mettre en place un exemple simple d’une page HTML utilisant ROSLibjs pour communiquer avec un système ROS2. L’objectif du tutoriel sera d’utiliser un publisher et un subscriber depuis notre page web pour interagir avec un turtlebot3 simulé dans Gazebo.

Prérequis: Utiliser une installation ROS2 avec Gazebo

ROS2

Vous pouvez vous connecter au site TheConstruct pour acceder à des machines virtuelles préconfigurées avec une installation ROS. Ce tutoriel est realisé avec ROS Humble.

Si vous voulez effectuer le tutoriel sur votre installation local, vous devez avoir ROS2 installé (https://docs.ros.org/en/humble/Installation.html), avoir configuré un workspace (https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html) et avoir installé le turtlebot3.

# pour installer tous les packages du turtlebot3
# remplacez humble par votre distro ROS2
cd ~/ros2_ws
colcon build
source install/setup.bash
sudo apt-get install ros-humble-turtlebot3*
# n'oubliez pas d'exporter le modèle de Turtlebot3 que vous souhaitez utiliser
export TURTLEBOT3_MODEL=waffle_pi

Nous allons ensuite lancer la simulation du turtlebot3 dans gazebo. Le turtlebot3 va publier les topics que nous allons utiliser dans le tutoriel.

Partie 1: Concepts

rosbridge_suite (https://github.com/RobotWebTools/rosbridge_suite) avec le node rosbridge-server fournit un serveur WebSocket qui donne accès aux fonctionnalités de ROS pour des programmes non-ROS. WebSocket est un protocole de communication qui permet une communication bidirectionnelle entre les clients et les serveurs à travers une connexion unique et durable. Des clients roslib ont été développés dans differents languages de programmation (Python, Rust, Java, Javascript). rosbridge_server permet donc une intégration entre ROS avec un large éventail de technologies, notamment des applications Web, des appareils mobiles, des environnements de simulation. Dans ce tutoriel nous allons apprendre à utiliser roslibjs qui permet d’interagir avec l’ecosystème ROS en utilisant Javascript. Nous allons créer ensemble une interface web simple permettant d’interagir avec un robot simulé sur Gazebo.

Partie 2: Implémentation

Nous allons dans un premier temps créer une page web index.html dans le dossier webpage_ws. Cette page web html execute du javascript pour utiliser ROSlibjs et déclarer notre publisher et notre subscriber:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ROS2 ROSLIBjs example</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <h1>ROS2 ROSLIBjs example</h1>
    <div class="container">

        <!-- Inputs pour publier le message Twist sur le topic cmd_vel -->
        <div>
            <label for="linearSpeed">Linear Speed:</label>
            <input type="number" id="linearSpeed" step="0.1" value="0">
            <label for="angularSpeed">Angular Speed:</label>
            <input type="number" id="angularSpeed" step="0.1" value="0">
            <!-- Appelle la fonction submitInputsTwist qui va publier un Twist message -->
            <button onclick="submitInputsTwist()">Publish Twist</button>
        </div>

        <!-- Zone de texte pour afficher les messages reçu par le subscriber d'odom -->
        <div>
            <h2>Received Odometry</h2>
            <textarea id="odometryData" readonly></textarea>
        </div>
        
        <!-- Joystick pour controler le robot en publiant sur cmd_vel -->
        <div id="joyDiv" style="width:200px;height:200px;margin-bottom:20px;"></div>
    </div>
    
    
    <!-- Pour importer roslibjs -->
    <script src="https://s3.eu-west-1.amazonaws.com/rosject.io/js/roslib.min.js"></script>

    <!-- La repository github du joystick https://github.com/bobboteck/JoyStick -->
    <script src="https://github.com/bobboteck/JoyStick/releases/download/v2.0.0/joy.min.js"></script>

    <!-- Javascript -->
    <script>

        // On déclare notre client
        var ros = new ROSLIB.Ros();

        var rosbridgeUrl = 'ws://localhost:9090'; // Remplacer localhost:9090 par l'url rosbridge_server URL (et ne pas ajouter:port)

        // Connecte au ROS2 environment
        ros.on('connection', function () {
            console.log('Connected to ROS1 environment.');
        });

        // Gérer les cas de déconnection
        ros.on('error', function (error) {
            console.error('Error connecting to ROS1 environment:', error);
        });

        ros.on('close', function () {
            console.log('Connection to ROS1 environment closed.');
        });

        // Déclare les variable qui permettent d'interagir avec les topics ROS
        var twistTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/cmd_vel',
            messageType: 'geometry_msgs/Twist'
        });

        var odometryTopic = new ROSLIB.Topic({
            ros: ros,
            name: '/odom',
            messageType: 'nav_msgs/Odometry'
        });
        
        // Subscribe au topic odom et définit la fonction callback
        odometryTopic.subscribe(function (message) {
            console.log(message)
            // Change la valeur de la texte area avec le message reçu depuis le topic
            document.getElementById('odometryData').value = JSON.stringify(message, null, 2);
        });

        function publishTwist(linearSpeed, angularSpeed) {
            
            // Declare le Twist message pour pouvoir publier les valeurs en entrée de la fonction
            var twist = new ROSLIB.Message({
                linear: {
                    x: linearSpeed,
                    y: 0,
                    z: 0
                },
                angular: {
                    x: 0,
                    y: 0,
                    z: angularSpeed
                }
            });
            // Publie le Twist message sur le topic cmd_vel
            twistTopic.publish(twist);
        }

        // Connecte au ROS2 environment
        ros.connect(rosbridgeUrl);

        
        // La fonction appellée lorsque Publish Twist est cliqué
        function submitInputsTwist() {

            // Récupère les valeurs des inputs pour linearSpeed et angularSpeed
            var linearSpeed = parseFloat(document.getElementById('linearSpeed').value);
            var angularSpeed = parseFloat(document.getElementById('angularSpeed').value);
            
            publishTwist(linearSpeed, angularSpeed);
        }

        
        
        // Declare le joystick pour publier les données sur cmd_vel
        var Joy1 = new JoyStick('joyDiv', {}, function(stickData) {
            
            // Récupère les valeurs des axes du joysticks
            let angularSpeed = -stickData.x/50;
            let linearSpeed = stickData.y/50;
            
            // Declare le Twist message pour pouvoir le publier
            var twist = new ROSLIB.Message({
                linear: {
                    x: linearSpeed,
                    y: 0,
                    z: 0
                },
                angular: {
                    x: 0,
                    y: 0,
                    z: angularSpeed
                }
            });
            
            // Publie le Twist message sur le topic cmd_vel
            twistTopic.publish(twist);
        });
        
    </script>
</body>
</html>

Pour résumer le code ci-dessus:

  • On écrit notre page HTML qui va servir d’interface utilisateur.
  • Dans notre Javascript, on crée le client websocket ROSLib et on crée les fonctions qui seront appelées pour differents évenements de la websocket (connection, error, close).
  • On déclare ensuite les variables qui vont nous permettre d’interagir avec les topics.
  • On subscribe au topic /odom et on modifie la valeur du textarea odometryData dans le callback.
  • On crée la fonction publishTwist qui est appelée lorsque le bouton Publish Twist est appelé, elle permet de publier les valeurs.
  • On déclare le joystick et on appelle la fonction publishTwist pour publier sur le topic cmd_vel les valeurs des axes du joysticks.

Vous pouvez également ajouter le fichier CSS style.css:

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f5f5f5;
    color: #333;
}

h1 {
    text-align: center;
    margin-top: 20px;
}

.container {
    max-width: 600px;
    display: flex;
    flex-direction: column;
    margin: 20px auto;
    background-color: #fff;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    
    text-align: center;
}

label {
    display: inline-block;
    width: 120px;
    margin-bottom: 10px;
}

input[type="number"] {
    width: 80px;
    padding: 5px;
    border-radius: 5px;
    border: 1px solid #ccc;
    margin-right: 10px;
}

button {
    padding: 8px 16px;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background-color: #45a049;
}

textarea {
    width: 100%;
    height: 150px;
    padding: 10px;
    border-radius: 5px;
    border: 1px solid #ccc;
    resize: none;
} 

Voici le visuel de la page web:

Nous allons voir dans la partie suivante comment l’ouvrir en utilisant notre environnement de développement.

Partie 3: Tester le système

Pour tester l’interface exemple du tutoriel, vous devez dans un premier temps lancer la simulation du turtlebot3 avec la commande suivante dans un premier terminal:

export TURTLEBOT3_MODEL=waffle_pi
ros2 launch turtlebot3_gazebo turtlebot3_house.launch.py

Vous devez ensuite lancer rosbridge_server dans un second terminal:

ros2 launch rosbridge_server rosbridge_websocket_launch.xml

Les prochaines étapes sont seulement pour faire fonctionner l’exemple dans un rosject de theConstuct. Dans un nouveau terminal, vous devez lancer un server python pour hoster la page web via l’installation de theConstruct:

python3 -mhttp.server 7000

Ouvrez un terminal et lancez les commandes suivantes:

# pour obtenir l'url de la page web html
webpage_address
# pour obtenir l'adresse de la websocket fournit par l'installation theConstruct
rosbridge_address

Vous devrez utiliser l’adresse websocket rosbridge_address dans la variable rosbridgeUrl du code.

Si vous effectuez le tutoriel sur votre machine locale, vous pouvez ouvrir directement votre page html avec votre navigateur et l’adresse de la websocket ws://0.0.0.0:9090 (port par defaut utilisé par le node rosbridge_server).

Vous pouvez maintenant ouvrir l’interface créée precedemment en ouvrant le ficher index.html dans votre navigateur. Vous devriez obtenir le résultat suivant:

Dans la textarea, vous pouvez voir l’odometry du robot mis à jour à chaque message reçu. Vous devriez pouvoir également pouvoir déplacer le turtlebot3 en utilisant les textes inputs ou le joystick pour publier sur le cmd_vel.

Feedback

Cet article vous a plu ? Avez-vous des questions sur ce qui est expliqué ? Quoi qu’il en soit, n’hésitez pas à laisser un commentaire dans la section des commentaires ci-dessous, afin que nous puissions interagir et apprendre les uns des autres.

Si vous souhaitez en savoir plus sur d’autres sujets liés à ROS, faites-le nous savoir dans l’espace commentaires et nous ferons une vidéo ou un article à ce sujet.
Topics: ROS Q&A | ros2

 

Video Tutorial

Topics: python | ros_bridge | ros2 | web
Masterclass 2023 batch2 blog banner

Check Out These Related Posts

0 Comments

Pin It on Pinterest

Share This