Le microordinateur Raspberry Pi a différentes utilisations courantes dont le retro-gaming avec RetroPie. Nous allons voir dans ce tutoriels, comment installer, configurer et utiliser RetroPie sur un Raspberry Pi
Matériel
Raspberry Pi 4 ou autre carte compatibles
écran+clavier+souris
manette de jeux vidéo ou autre capteur
Quelques mots sur RetroPie
RetroPie est un logiciel qui s’intègre à un OS et permet de transformer sa machine en émulateur de console de jeux vidéo. Il permet donc de faire du retro-gaming et de rassembler sur une même machine d’anciens jeux vidéo qui étaient disponibles sur diverses consoles.
RetroPie est compatible avec les cartes suivantes
Raspberry Pi Zero/Zero2W/1/2/3/4/400 (Raspbian)
PC linux (Debian/Ubuntu)
Odroid-C1/C2 (Ubuntu)
ODroid-XU3/XU4 (Ubuntu)
L’installation de RetroPie sur un Raspberry Pi permet d’en faire une console de jeux vidéo pour toute la famille à moindre coût. Cela permet aussi de réaliser une borne d’arcade.
Téléchargement et installation d’un OS avec RetroPie (conseillé)
Pour installer un OS contenant RetroPie, vous pouvez télécharger une image correspondant à votre machine sur le site officiel et l’écrire sur une carte SD via Raspberry Pi Imager ou Balena Etcher.
Vous pouvez également utiliser le logiciel Raspberry Pi Imager et sélectionner l’OS souhaité pour le retro-gaming
Une fois l’image écrite sur la carte SD, vous pouvez l’insérer dans le Raspberry Pi puis allumer le Raspberry Pi. L’installation de RetroPie devrait se lancer automatiquement.
Configuration de la manette de jeux
Au lancement de EmulationStation, la première chose demandé est la configuration de la manette de commande de jeux qui vous servira pour naviguer à travers les menus. Branchez une manette de jeux et suivez les instructions. Vous pourrez changer ces paramètres plus tard.
Configurer votre station d’émulation
Une fois les commandes de votre manette définies pour pouvoir naviguer dans le menu de RetroPie, vous pouvez configurer votre système en fonction de votre besoin;
audio
localisation
configuration WiFi
activation SSH
mise à jour
Installation RetroPie packages
Une fois votre système configuré, il est temps d’installer des jeux sur votre émulateur.
Où trouver et comment Transférer des ROMs pour RetroPie
Les ROMS (Read-only Memory) sont des fichiers contenant les images de jeux vidéo. Il est possible de trouver des roms sur la toile. Voici quelques sites dont le premier est le plus sûr
N.B.: attention au licence d’utilisation. Il peut être illégal de télécharger certains jeux sous licence.
Une fois les fichiers téléchargés, créez une arborescence de dossier avec un dossier par console ~/retropie/roms/$CONSOLE (ie: atari ou gb). Vous pouvez copier les fichiers décompressés dans le dossier de la console en question.
N.B.: les fichiers reconnus par RetroPie ont généralement les extensions correspondant au console (.gb, .gba, etc.) ou des images de CD ISO (.img)
Pour transférer les jeux sur RetroPie, vous pouvez utiliser le dossier Samba partagé prévu sur RetroPie (\\RETROPIE\roms)
Ou utiliser une clé USB avec un dossier par console contenant les images des jeux vidéo . Lorsque vous insérez la clé USB dans le Raspberry Pi, le transfert devrait se faire automatiquement.
Pour que les jeux soient disponibles dans RetroPie, le logiciel EmulationStation doit être redémarré. (Menu > Quit > Restart EmulationStation )
Jouer et gérer les données de jeux
Une fois EmulationStation redémarré, les consoles et jeux disponibles apparaissent dans le menu principal.
Une fois le jeux sélectionné, il est possible de sortir du jeu, sauvegarder et charger avec les commandes suivantes (Hotkey default: bouton Select)
Hotkey Combination
Action
Hotkey+Start
Exit
Hotkey+Right Shoulder
Save
Hotkey+Left Shoulder
Load
Hotkey+Right
Input State Slot Increase
Hotkey+Left
Input State Slot Decrease
Hotkey+X
RGUI Menu
Hotkey+B
Reset
Terminal RetroPie
En cas de problème ou pour certaines opérations, vous aurez besoin de naviguer dans l’OS du RPi. Pour cela, il vous suffit de fermer EmulationStation (Menu>Quit>Exit EmulationStation)
Vous pourrez retrouver:
les fichiers Raspbian comme le fichier config.txt pour la configuration manuel du boot
sudo nano /boot/config.txt
les émulateurs installés
ls /opt/retropie/emulators
la configuration des joysticks
/opt/retropie/configs/all/retroarch/autoconfig
Problèmes courants
RetroPie ne boot pas
Si RetroPie ne boot pas du tout:
carte SD corrompue
mauvaise version de l’OS
Lors du premier démarrage, RetroPie reste bloqué sur le terminal de démarrage et EmulationStation ne se lance pas.
Nous allons voir dans ce tutoriel comment installer le logiciel Arduino IDE et CLI sur Raspberry Pi et ainsi combiner les forces des deux systèmes.
Vérifier la configuration de votre système
Pour savoir quelle version de l’IDE télécharger et installer, vous devez connaitre les spécificités de votre système. Notamment l’architecture du noyau (Linux kernel). Il existe plusieurs commandes possibles.
uname -a #display os and kernel info
cat /proc/version
architecture
kernel
i386/i486/i586/i686/armv7l
32 bit
x86_64(Intel)/aarch64(Arm)/armv8
64 bit
cat /proc/cpuinfo #cpu architecture
La commande la plus directe est de deamnder sur combien de bit est encodé une variable LONG
getconf LONG_BIT # result is 32 or 64
Installation d’Arduino IDE
Sur la page de téléchargement d’Arduino, sélectionnez la version correspondante à votre système et téléchargez-la.
Vous pouvez effectuer cette procédure en ligne de commande. en connaissant le nom du fichier arduino-1.8.19-linux<architecture>.tar.xz
pour mon système aarch64 :arduino-1.8.19-linuxaarch64.tar.xz
Voud devez alors accordez les droits en lecture et écriture
sudo chmod a+rw /dev/ttyACM0
Bonus: Installation de Arduino-CLI sur Raspberry Pi
Si votre système n’a pas accès à une interface graphique (headless, accès SSH), vous pouvez utiliser les lignes de commandes pour créer, compiler et téléverser vos scripts Arduino.
Un autre outil plus récent et plus puissant est Arduino-CLI que vous pouvez installer avec la commande
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
mv bin/* Arduino/
cd Arduino
chmod a+x arduino-cli
alias arduino-cli='sudo ./arduino-cli'
Mettre à jour la liste des cartes supportées
arduino-cli core update-index
Installer ensuite le gestionnaire de cartes
arduino-cli core install arduino:avr
Vérifiez les cartes connectées au Raspberry Pi et noter les noms FQBN
Pour récolter des données sur internet, il est possible de créer un Web crawler ou Web scraping avec Python. Un robot d’exploration du Web est un outil qui permet d’extraire des données d’une ou plusieurs pages Web.
Configuration de l’environnement Python
Nous partons du principe que Python3 et pip sont installés sur votre machine. Vous pouvez également utiliser un environnement virtuel pour conserver un projet propre et maitriser les versions de librairies de votre web crawler Python.
Nous allons tout d’abord installer la librairie requests qui permet de faire des requêtes HTTP au serveur pour récupérer les données.
python -m pip install requests
Pour analyser et naviguer dans les données du Web, nous utilisons la librairie Beautiful Soup qui permet de travailler avec des scripts à balises comme le HTML ou le XML
python -m pip install beautifulsoup4
Enfin, nous installons la librairie Selenium qui permet d’automatiser les tâches d’un navigateur Web. Elle permet d’afficher des pages web dynamiques et de réaliser des actions sur l’interface. Cette librairie permet à elle seule de faire du Web scraping sur internet car elle peut travailler avec un site web dynamique qui fonctionne avec JavaScript.
python -m pip install selenium
Pour faire fonctionner Selenium avec Mozilla, vous aurez besoin de télécharger Geckodriver
Récupérer une page Web avec resquest
Imaginons que nous souhaitions récupérer les données techniques d’une carte Arduino, nous pouvons charger la page désirée avec requests et bs4
En observant la structure de la page, vous pouvez repérer les balises, classes, identifiants ou textes qui vous intéressent. Dans cet exemple, nous récupérons
le nom de la carte
la description de la carte
N.B.: Vous pouvez retrouver la structure de la page web sur votre navigateur avec clique-droit sur la page puis “Inspecter”
import requests
from bs4 import BeautifulSoup
print("Starting Web Crawling ...")
#website to crawl
website="https://docs.arduino.cc/hardware/uno-rev3/"
#google search
#keywords = ["arduino","datasheet"]
#googlesearch = "https://www.google.com/search?client=firefox-b-d&q="
#search = "+".join(keywords)
#website = googlesearch+search
# get page
page = requests.get(website)
#extract html data
content = BeautifulSoup(page.text, 'html.parser')
# extract tags
h1_elms = content.find_all('h1')
print("Board : ",h1_elms)
#get element by class
description = content.find(class_="product-features__description").text
print("Description : ",description)
Starting Web Crawling ...
Board : [<h1>UNO R3</h1>]
Description : Arduino UNO is a microcontroller board based on the ATmega328P. It has 14 digital input/output pins (of which 6 can be used as PWM outputs), 6 analog inputs, a 16 MHz ceramic resonator, a USB connection, a power jack, an ICSP header and a reset button. It contains everything needed to support the microcontroller; simply connect it to a computer with a USB cable or power it with a AC-to-DC adapter or battery to get started. You can tinker with your UNO without worrying too much about doing something wrong, worst case scenario you can replace the chip for a few dollars and start over again.
On pourrait imaginer boucler cet opération sur une liste d’URL pour plusieurs cartes.
Avec cette méthode, on ne peut malheureusement pas charger la liste détaillé des spécification “Tech Specs” pour cela nous devons nous servir du navigateur.
Mettre en place un Web Crawler avec Selenium
Pour charger une page rien de plus facile
from selenium import webdriver
GECKOPATH = "PATH_TO_GECKO"
sys.path.append(GECKOPATH)
print("Starting Web Crawling ...")
#website to crawl
website="https://docs.arduino.cc/hardware/uno-rev3/"
#create browser handler
browser = webdriver.Firefox()
browser.get(website)
#browser.quit()
Validation des cookies
En affichant la page, vous aller certainement tomber sur la bannière de cookie qu’il faudra valider ou non pour continuer la navigation. Pour cela, il faut retrouver et cliquer sur le bouton “accepter”
Comme la page est affiché dans le navigateur, il faut un certain temps pour qu’elle charge les données et que toutes les balises soient affichées. Pour attendre le chargement, vous pouvez attendre un temps arbitraire
browser.implicitly_wait(10)
Ou attendre qu’une balise particulière soit présente comme le bouton d’acceptation des cookies
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
def waitForElement(locator, timeout ):
elm = WebDriverWait(browser, timeout).until(expected_conditions.presence_of_element_located(locator))
return elm
myElem =waitForElement((By.CLASS_NAME , 'iubenda-cs-accept-btn'),30)
N.B: Si vous rencontrez d’autre problème (élément inconnu , bouton non cliquable, etc.) dans le script alors qu’il n’y a pas de soucis sur la page Web, n’hésitez pas à utiliser la fonction time.sleep()
Chercher et appuyer sur un élément DOM
Pour afficher les spécifications techniques, le script doit cliquer sur l’onglet ‘Tech Specs’. Il faut donc trouver l’élément à partir du texte. Pour cela, il y a deux méthodes: tester le texte de l’élément ou utiliser Xpath
#get element by text
btn_text = 'Tech Specs'
btn_elms = browser.find_elements(By.CLASS_NAME,'tabs')[0].find_elements(By.TAG_NAME,'button')
for btn in btn_elms:
if btn.text == btn_text:
btn.click()
spec_btn = browser.find_element(By.XPATH, "//*[contains(text(),'Tech Specs')]")
spec_btn.click()
Récupérer les données désirées
Une fois la page souhaitée chargée, vous pouvez récupérer les données
Soit toutes les données qui sont affichées sous forme de tableau
#get all rows and children
print("Tech specs")
print("-------------------------------------")
tr_elms = browser.find_elements(By.TAG_NAME,'tr')
for tr in tr_elms:
th_elms = tr.find_elements(By.XPATH, '*')
if len(th_elms)>1:
print(th_elms[0].text, " : ", th_elms[1].text)
Starting Web Crawling ...
Page is ready!
Tech specs
-------------------------------------
Name : Arduino UNO R3
SKU : A000066
Built-in LED Pin : 13
Digital I/O Pins : 14
Analog input pins : 6
PWM pins : 6
UART : Yes
I2C : Yes
SPI : Yes
I/O Voltage : 5V
Input voltage (nominal) : 7-12V
DC Current per I/O Pin : 20 mA
Power Supply Connector : Barrel Plug
Main Processor : ATmega328P 16 MHz
USB-Serial Processor : ATmega16U2 16 MHz
ATmega328P : 2KB SRAM, 32KB FLASH, 1KB EEPROM
Weight : 25 g
Width : 53.4 mm
Length : 68.6 mm
Specific data
-------------------------------------
Main Processor : ATmega328P 16 MHz
PS D:\Formation\Python\WebCrawler>
Récupérer des données sur différentes pages
Une fois que vous maitrisez ces outils et avez une bonne idée des données à récupérer et de la structure des pages Web, vous pouvez scraper des données sur plusieurs pages. Dans ce dernier exemple, nous récupérons les données techniques de différentes cartes Arduino. Pour cela, nous créons une boucle qui va exécuter le code précédent sur une liste de site
Nous allons voir dans ce tutoriel comment créer une application de bureau avec le framework Electron. Cet environnement de programmation permet de développer des IHM à l’aide des langages Web JavaScript, HTML et CSS compatible sur plusieurs OS.
Mise en place de l’environnement de programmation
Pour ce tutoriel, nous utilisons l’éditeur de code VS Code.
Le framework Electron fonctionne avec le logiciel Node.js. Téléchargez et installez la dernière version
ou entrez les commandes suivantes sur Linux
sudo apt-get install nodejs npm
Vérifier les versions installées. Cela vous servira pour la compatibilité des librairies
node -v
npm -v
Dans le terminal de VSCode, créer votre répertoire de travail
mkdir ElectronApp && cd ElectronApp
Dans le répertoire de l’application, entrer la commande d’initialisation pour créer les fichiers par défaut
npm init
Entrez les informations demandées. Notez que Electron prend le fichier main.js en point d’entrée (entry point).
Press ^C at any time to quit.
package name: (electronapp)
version: (1.0.0)
description: custom electron app for dev and tutorials
entry point: (index.js) main.js
test command:
git repository:
keywords:
author: aranacorp
license: (ISC) MIT
About to write to D:\Formation\Javascript\Electron\ElectronApp\package.json:
{
"name": "electronapp",
"version": "1.0.0",
"description": "custom electron app for dev and tutorials",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron ."
},
"author": "aranacorp",
"license": "MIT"
}
Vous pouvez ensuite installer le paquet electron
npm install --save-dev electron
Une fois le fichier package.json créé, ajouter la ligne suivante dans scripts
"start": "electron ."
Ce scirpt permet de lancer l’application à l’aide la commande
npm start
Création de la première application Electron
Dans cet exemple, nous allons récupérer les versions de node et electron comme dans le tutoriel de base. Nous allons également ajouter un champ de saisie pour définir une éventuelle URL.
Pour créer l’application, nous allons créer 5 fichiers
main.js gère le cycle de vie de l’application
index.html contient la page HTML
./src/ac_style.css contient le style de la page HTML
Nous allons créer une application React Native qui servira de client Websockets et pourra communiquer avec un serveur distant. WebSockets est un protocole populaire de communication web simple et robuste permettant la communication en temps réel entre client et serveur.
Matériel
Appareil Android
Ordinateur pour la programmation
Un câble USB pour connecter l’appareil Android au PC
Configuration du projet React Native
Pour communiquer via Websocket nous allons utiliser la librairie Websocket, react-use-websocket
npm install --save react-use-websocket
Utilisation de la librairie
A partir de la librairie, nous importons les objets et fonctions qui nous intéresse
import useWebSocket, { ReadyState } from 'react-use-websocket';
ReadyState état de la connexion avec le serveur
useWebScoket permet d’initialiser une connexion websockets
Nous créons ensuite un composant fonctionnel avec les états désirés
Nous allons créer une application React Native qui permet de lire ou écrire un fichier dans un espace de stockage interne ou externe. Avoir accès au fichier du système peut être intéressant pour sauvegarder les données d’une session de l’application à une autre ou pour utiliser ou modifier les données d’un fichier.
Matériel
Appareil Android
Ordinateur pour la programmation
Un câble USB pour connecter l’appareil Android au PC
Configuration du projet React Native
Pour venir lire et écrire dans un fichier nous allons utiliser la librairie File System, react-native-fs
npm install --save react-native-fs
Utilisation de librairie
A partir de la librairie, nous importons les objets et fonctions qui nous intéresse
import { DocumentDirectoryPath, writeFile, readDir, readFile, unlink } from 'react-native-fs'; //send files for testing
DocumentDirectoryPath permet de récupérer le chemin d’accès des fichiers de l’application
writeFile permet d’écrire dans un fichier
readDir permet de lire un répertoire
readFile permet de lire un fichier
unkink permet de supprimer un fichier
Nous créons ensuite un composant fonctionnel avec les états désirés
Grâce à cette application, nous pouvons afficher le contenu d’un répertoire, lire, écrire et supprimer un fichier
Lire et écrire un fichier dans un espace de stockage externe
Par défaut, une application n’a d’autorité que sur son propre répertoire
Il est possible de donner les droits d’accès à un espace de stockage externe comme une clé USB.
Pour se faire, vous pouvez accorder les droits depuis l’interface Android. Aller dans les paramètres > App et notifications > Gestionnaire des autorisations > Fichiers et contenus multimédia
Brancher la clé USB à votre appareil, à l’aide d’adb repérer le chemin d’accès de l’espace de stockage dans ls /storage/ (ici: /storage/70A8-C229)
Une fois l’autorisation activée, vous pourrez afficher et créer des fichiers sur la clés USB
Code complet de gestion de fichier avec React Native
Nous allons voir comment mettre en place une communication entre un serveur et un client en utilisant le protocole Websockets sous Python. WebSockets est un protocole de communication web simple et robuste permettant la communication en temps réel.
Installation de la librairie Websockets
Pour utiliser les WebSockets avec Python, nous installons le paquet nécessaire..
python3 -m pip install websockets
Nous utilisons aussi la librairie asyncio qui permet de faire de la programmation asynchrone pour le développement de serveur performant
Récupérer l’adresse IP du serveur
Comme dans toute communication internet, pour établir une connexion entre le client et le serveur, il faut connaître l’addresse IP du serveur.
Pour récupérer l’adresse IP de la machine serveur vous pouvez utiliser les commandes ipconfig (Windows) ou ifconfig/ ip addr (Linux) (ici: 192.168.1.59)
Il est aussi possible d’utiliser le paquet socket dans le script Python
Notez l’adresse, vous l’utiliserez dans le code client.
Code Python pour le serveur WebSocket
Pour lancer le serveur, nous définissons une fonction main qui va ouvrir le serveur sur le port 8765 et le faire tourner en boucle. Nous appelons aussi la fonction callback echo() qui va gérer la réception de message. Dans cet exemple, nous renvoyons le message tel quel au client.
#!/usr/bin/env python
# python3 -m pip install websockets
import asyncio
from websockets.server import serve
def getIpAddress():
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipaddress = s.getsockname()[0]
s.close()
return ipaddress
ipaddress = getIpAddress()
port = 8765
async def echo(websocket):
async for message in websocket:
print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
await websocket.send(message)
async def main():
print("Server is activated on ws://{}:{}".format(ipaddress,port))
#async with serve(echo, "localhost", 8765):
async with serve(echo, "0.0.0.0", port):
await asyncio.Future() # run forever
asyncio.run(main())
N.B.: pour que le serveur soit visible sur le réseau extérieur à l’ordinateur vous devez spécifier l’adresse “0.0.0.0” à la place de “localhost”
Code Python pour le client WebSocket
Dans le code client, nous nous connectons au serveur en spécifiant l’adresse IP et le port. Puis, nous envoyons un message. Enfin on attend le message de réponse pour l’afficher.
#!/usr/bin/env python
# python3 -m pip install websockets
import asyncio
from websockets.sync.client import connect
def hello():
#with connect("ws://localhost:8765") as websocket:
with connect("ws://192.168.1.52:8765") as websocket:
websocket.send("Hello world!")
message = websocket.recv()
print(f"Received from server : {message}")
hello()
Résultat
Dans un terminal, lancez d’abord le script serveur: python websocket_server.py
Dans un second terminal, lancez ensuite le script client ; python websocket_client.py
Échange de message JSON via WebSocket
Le format JSON(JavaScript Object Notation) est un format d’échange de donnée très populaire dans la communication web. NousPour échanger des données JSON entre serveur et client nous utilisons la libraire pré-installée json
Dans le script client, nous allons envoyer une requête au format JSON. Le serveur va recevoir cette requête vérifier les valeurs et envoyer une réponse avec le résultat de la validation.
Les fonctions à connaitre pour gérer le format JSON sont:
json.loads() pour passer d’un String à un dict
json.dumps() pour passer d’un dict à un String
D’autre format Python peuvent être converti en leur équivalent JSON
Python
JSON
dict
object
list, tuple
array
str
string
int, float, int
number
True
true
False
false
None
null
script client
#!/usr/bin/env python
# python3 -m pip install websockets
import json
import asyncio
from websockets.sync.client import connect
jsondata = {"type": "setParam", "param1": 30, "param2": 2.3}
jsonwrong = {"type": "setParam", "param1": 30, "param2": -2.3}
jsonunkn = {"type": "setData", "param1": 30, "param2": 2.3}
def hello():
with connect("ws://192.168.1.52:8765") as websocket:
websocket.send("Hello world!")
message = websocket.recv()
print(f"Received from server : {message}")
websocket.send(json.dumps(jsondata))
message = websocket.recv()
print(f"Received from server : {message}")
websocket.send(json.dumps(jsonwrong))
message = websocket.recv()
print(f"Received from server : {message}")
websocket.send(json.dumps(jsonunkn))
message = websocket.recv()
print(f"Received from server : {message}")
hello()
script serveur
#!/usr/bin/env python
# python3 -m pip install websockets
import json
import asyncio
from websockets.server import serve
def getIpAddress():
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipaddress = s.getsockname()[0]
s.close()
return ipaddress
ipaddress = getIpAddress()
port = 8765
async def echo(websocket):
async for message in websocket:
print("received from {}:{} : ".format(websocket.remote_address[0],websocket.remote_address[1]) + message)
if('{' not in message):
await websocket.send(message)
else:
request = json.loads(message)
answer = {}
if(request['type'] == 'setParam'):
answer['type'] = request['type']
if(request['param1']<100 and request['param2']>1.2):
answer['valid'] = True
for key, val in request.items():
print("\t"+key+": ", val)
else:
answer['valid'] = False
else:
answer['type'] = 'unknown'
answer['valid'] = False
await websocket.send(json.dumps(answer))
async def main():
print("Server is activated on ws://{}:{}".format(ipaddress,port))
#async with serve(echo, "localhost", 8765):
async with serve(echo, "0.0.0.0", port):
await asyncio.Future() # run forever
asyncio.run(main())
Dans ce tutoriel, nous allons voir comment créer et lancer des script Python sous ROS2. Vous pourrez ainsi créer vos propres noeuds et commencer à développer sous ROS.
Créer un espace de travail
Une bonne pratique pour développer sous ROS2 est de créer des workspaces dans lesquels on va installer les paquets désirés, séparés de l’installation principale.
Installation de colcon
sudo apt install python3-colcon-common-extensions
Créer le dossier
mkdir -p ~/tuto_ws/src
cd ~/tuto_ws
Copier ensuite un projet type, comme tutoriel contenant turtlesim
git clone https://github.com/ros/ros_tutorials.git -b iron
Puis construisez le projet à l’aide de la commande
colcon build
Pour charger votre workspace dans un nouveau terminal
source /opt/ros/iron/setup.bash
cd ~/ros2_ws
source install/local_setup.bash
N.B.: vous pouvez mettre les commandes suivantes dans un fichier ros_profile pour le source en une seule commande “source ros_profile”
Créer un Package python
ROS2 offre un outil simple pour créer l’architecture de fichiers d’un paquets Python ou C++. Vous devez alors spécifier au moins le nom du paquet (my_paquet). Il est possible également de donner le nom du nœud.
Dans le répertoire ~/ros2_sw/src, entrez la commande suivante
Pour lancer un noeud dans un terminal, vous devez sourcer le projet
source /opt/ros/iron/setup.bash
cd ~/ros2_ws
source install/local_setup.bash
Dans trois terminaux différents, lancez les commandes suivantes
ros2 run turtlesim turtlesim_node #terminal1
ros2 run projects read_turtle #terminal2
ros2 run projects control_turtle #terminal3
Résultat
Vous pouvez voir la tortue décrire la forme d’un cercle et la position évoluer dans la fenêtre du subscriber
Lancer un noeud avec des arguments
Il est possible de configurer les noeuds lors de leur exécution. Dans cet exemple, nous allons définir des paramètre d’entrée pour la vitesse linéaire et angulaire. Nous allons donc modifier le code du Publieur ci-dessus
Dans l’initialisation du noeud, nous déclarons les paramètres avec les valeurs par défaut
Dans ce tutoriel, nous allons voir comment installer ROS2 sur une machine Linux et notamment un Raspberry Pi 4 avec une distribution Ubuntu. ROS2 est un framework intéressant à abordé lorsqu’on travaille sur des systèmes embarqués comme les robots.
Matériel
Ordinateur avec accès internet
Carte SD 32Go
Raspberry Pi+écran HDMI+clavier/souris
Ce tutoriel peut être suivit pour d’autres machines Linux
Téléchargement Ubuntu et configuration de la carte SD
Nous allons voir comment configurer la carte SD pour installer ROS2 (Iron Irwini) sur Raspberry Pi. Cette version de ROS2 est compatible avec Ubuntu Jammy.
Pour cela télécharger l’image d’Ubuntu (Jammy jellyfish) ou sélectionnez l’OS sous Raspberry Pi Imager > General OS > Ubuntu > Ubuntu Desktop 22.04.3 LTS (64bits)
N.B.: vous pouvez retrouver la compatibilité des versions entre ROS et OS et les noms des versions Ubuntu pour vérifier que vous installez les bonnes versions. Sélectionnez la version 64bits pour un meilleur support (tier1)
Installer l’image de l’OS à l’aide de Raspberry Pi Imager sur la carte SD
Une fois l’image écrite sur la carte SD vous pouvez l’insérer dans le Raspberry Pi puis le mettre sous tension.
Vous pouvez ensuite suivre les instructions de configuration sur l’écran du Raspberry Pi.
Configurer la connexion à distance
Vous pouvez, si vous le désirez, configurer la connexion à distance sur Raspberry Pi. Cette étape est optionnelle mais peut vous simplifier la vie lorsque vous développerez sur ROS2 sous Raspberry Pi.
N.B.: sur Ubuntu, pour vous connecter à distance sans moniteur, vous devez modifier le fichier /boot/firmware/config.txt
Pour l’installation de ROS2, vous devez tout d’abord vérifier que le téléchargement de dépôt Universe est activé. Dans Software & Updates > Ubuntu Software
Le Bluetooth Low Energy (BLE) a une limitation connue d’une 20Bytes pour la longueur des chaînes envoyées. Ils existent des méthodes pour outrepasser cette limite.
Matériel
Dans ce tutoriel, nous envoyons des données à partir d’une application Android, développée sous React Native, vers une ESP32. Les méthodes décrites peuvent être valables avec d’autres appareils.
Appareil Android
ESP32 BLE
Limitation de 20 bytes du BLE
L’application développée sous React Native est tout à fait capable d’envoyer de longues chaînes de caractères sous forme de paquet de 20bytes par défaut. Sans modification du tutoriel précédent voici la valeur reçue côté ESP32. Seul le dernier paquet est gardé en mémoire.
01:48:39.734 -> ESP32BLE server ready
01:48:40.493 -> Server address:3c:61:05:31:5f:12
01:48:41.672 -> Client connected
01:48:48.169 -> Charac value: Helloworldthisisalon
01:48:48.253 -> Charac value: gstringletseewhatcom
01:48:48.374 -> Charac value: esout;
01:48:48.374 -> this is the last packet
Résumé des méthodes pour envoyer de longues chaînes via BLE
Récupérer plusieurs paquets (côté récepteur)
Envoyer la longue chaîne sous forme de petits paquets (côté émetteur)
Augmenter la limite MTU de 23 bytes à 512 bytes
Récupérer plusieurs paquets
Si l’appareil qui envoie les messages est capable de gérer l’envoie de chaine de caractères qui dépassent la limite MTU, comme c’est le cas dans notre exemple, il ne reste plus qu’à configurer le module récepteur pour concaténer les différents paquets reçus. Pour cela, nous utilisons un caractères de fin de chaîne, par exemple “;”.
Dans la fonction onWrite de la caractéristique du module ESP32BLE, nous ajoutons un test de fin de chaîne et une variable longMsg qui nous servira de tampon.
std::string longMsg;
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.print("Charac value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
if(value.find(";") != -1){
//Serial.println("this is the last packet");
longMsg = longMsg + value;
Serial.print("longMsg: ");
for (int i = 0; i < longMsg.length(); i++)
Serial.print(longMsg[i]);
Serial.println();
//do whatever you want with longMsg then erase
longMsg = "";
}else{
longMsg = longMsg + value;
}
}
}
};
Envoyer des paquets de taille prédéfinie
Si l’appareil qui envoie les données ne gère pas les messages de taille supérieure au MTU, alors il est possible de séparer la chaîne de caractères en paquets de taille prédéfinie (chunksize). Cette méthode permet de maitriser la taille des paquets envoyés.
Dans le projet React Native, nous créons une fonction qui va transformer la longue chaîne de caractère en Array de bytes que nous allons envoyez par paquets.
const sendLongMessage = async (data: string, chunksize: number) => {
console.log("data : ",data)
var bytes = convertStringToByteArray(data)
var times = Math.ceil(bytes.length/chunksize);
var packets = [];
console.log("split data ",times," times");
//console.log("bytes: ",bytes)
var i=0
for(var time=0;time<times;time++){
var packet = bytes.slice(time*chunksize, (time+1)*chunksize)
packets.push(packet)
console.log(time," : ",byteArrayToString(packet))
sendMessage(byteArrayToString(packet));
await delay(100);
}
}
N.B.: une fonction de retard peut être introduite pour laisser le temps au message d’être envoyé. delay(100)
Par défaut, la librairie react-native-ble-manager envoie des paquets de 20bytes, Il existe une méthode permettant de spécifier au module BLE de modifier la taille du Maximum Transmission Unit (MTU)
Dans le code de l’application, pendant la connexion, avant de récupérer les services, ajouter une requête MTU
BleManager.requestMTU(device.id, 512).then(
(mtu) => {
setMTU(mtu);
}
) //request the MTU size in bytes
Lors de l’envoie du message, vous pouvez spécifier la taille maximum du message en bytes, “mtu”, dans la fonction BLEManager.write()
BleManager.write(
selectedDevice.id,
serviceid,
caracid,
buffer.toJSON().data,
mtu // or 512
).then(() => {
// Success code
console.log("Write: " + buffer.toJSON().data);
})
Côté ESP32, il existe une méthode de la librairie BLEDevice permettant de définir la taille du MTU.
BLEDevice::setMTU(512); //between 23 and 517 (bluetooth 4.2)
N.B.: Dans cet exemple (Android+ESP32), seule la définition du nombre maximum de bytes dans la fonction BLEManager.write() permet d’augmenter la limite. Nous laissons les autres infos qui pourraient être utiles pour une autre configuration (iOS, HM10, etc.)
Une fois le code modifié, lorsqu’on renvoie la même chaîne de caractère, on reçoit la totalité de sa valeur dans la caractéristiques BLE
Applications
Augmenter la taille des messages envoyés au module BLE
Imiter le fonctionnement du Bluetooth classic de manière ponctuelle