This tutorial is created by Rosbotics Ambassador 012 Alessandro
Rosbotics Ambassador Program https://www.theconstruct.ai/rosbotics-ambassador/)
In questo tutorial verrà mostrata un’implementazione di un nodo subscriber in grado di leggere messaggi di diverso tipo e provenienti da molteplici topic, gestiti attraverso una singola funzione di callback.
Risorse
- Rosject utilizzato in questo tutorial
- Piattaforma: The Construct
- Corsa: ROS Basics In 5 Days: https://app.theconstructsim.com/courses/55
Come utilizzare i Rosject
Nel caso non si volesse installare ROS Noetic sul proprio sistema e fare il set up dell’ambiente di sviluppo, è possibile utilizzare i
Rosject offerti da The Construct per poter testare i contenuti del tutorial o per seguirlo passo passo.
Per fare ciò sarà sufficiente seguire il link indicato nelle risorse e cliccare su “Run”. In questo modo si avrà accesso a una copia del
Rosject utilizzato all’interno del tutorial.
Aprire terminal e IDE
Per aprire un nuovo terminale e avere accesso all’IDE forniti dal Rosject, sarà possibile utilizzare la console in basso a destra.
Prerequisiti
Per poter seguire il tutorial passo passo sarò necessario avere il nodo publisher, che pubblica su diversi topic, attivo e creare un package dove poter inserire il codice per il subscriber.
Per iniziare eseguiamo il nodo publisher. Sarà sufficiente aprire il terminale dalla console (vedi Risorse) e inserire i seguenti comandi nelle rispettive schede del terminale:
Terminale 1:
roscore
Terminale 2:
cd catkin_ws
rosrun publisher publisher.py
Quindi è possibile verificare il corretto funzionamento del nodo aprendo una seconda finestra al’interno del terminale e osservando l’output del comando rostopic list
.
L’output previsto è il seguente:
Terminale 3:
rostopic list
/chatter0
/chatter1
/chatter2
/rosout
/rosout_agg
Procediamo quindi a creare il package per il subscriber:
Terminale 3:
cd src
catkin_create_pkg multiple_subscriber rospy std_msgs
mkdir multiple_subscriber/script
Situazione di partenza
Al momento abbiamo eseguito il nodo publisher che pubblica su 3 topic messaggi di vario tipo. In particolare:
- /chatter0 pubblica messaggi di tipo String
- /chatter1 pubblica messaggi di tipo Float64
- /chatter2 pubblica messaggi di tipo Bool
Vediamo quindi come possiamo gestire tutti e tre i topic, creando un subscriber in grado di leggere i messaggi dai chatter e di gestirli con una singola funzione di callback, differenziando il risultato di quest’ultima sfruttando l’uso di parametri.
Creazione del file multiple_sub.py
Proseguiamo creando il file necessario a definire il nostro subscriber e tutte le sue funzioni.
Terminale 3:
touch multiple_sub/script/multiple_subscriber.py # Crea il file
chmod +x multiple_sub/script/multiple_subscriber.py # Garantisce i permessi di esecuzione
cd ..
catkin_make
Implementazione del subscriber
Partiamo quindi dallo specificare un interprete per il nostro codice in Python, dall’importare i moduli necessari (rospy e in questo caso std_msgs/String, std_msgs/Float64, std_msgs/Bool) e dallo scrivere un main che inizializzi il nodo e invochi rospy.spin() per poter eseguire le callback del nostro subscriber.
main
multiple_subscriber.py
import rospy
from std_msgs.msg import String, Float64, Bool
if __name__=="__main__":
rospy.init_node("multiple_subscriber")
topics = {"chatter0": [String, "Argomento passato da chatter0"], "chatter1": [Float64, "Argomento passato da chatter1"], "chatter2": [Bool, "Argomento passato da chatter2"]}
multiple_subscribe()
rospy.spin()
All’interno della funzione abbiamo definito anche topics, un dizionario contenente le specifiche dei topic che vogliamo andare a leggere, seguendo la seguente struttura:
{"nome_topic": [Tipo, Argomento]}
Per ogni chiave topic abbiamo quindi definito una lista contente il tipo del messaggio inviato dal topic e un argomento (in questo caso una stringa che esplicita di essere l’argomento passato per lo specifico topic) .
multiple_subscribe
La funzione multiple_subscribe()
sarà definita perché il nodo possa seguire i 3 topic e perché i messaggi pubblicati possano innescare la callback.
multiple_subscriber.py
def multiple_subscribe():
for t in topics:
rospy.Subscriber(t, topics[t][0], callback, callback_args=topics[t][1])
Il nodo segue quindi ciascuno dei topic definiti nel dizionario, aspettandosi messaggi del relativo tipo, invocando una funzione callback e passando il relativo argomento tramite il parametro callback_args.
callback
Vediamo una semplice implementazione della callback per poter gestire i tre topic.
multiple_subscriber.py
def callback(data, args):
rospy.loginfo(f"Ricevuto: {data.data}")
print(args)
print('\n')
In questo caso andiamo a stampare come info di ROS il contenuto del messaggio arrivato alla callback e stampiamo l’argomento passato corrispondente. Entrambi dipenderanno da quale topic ha innescato la callback e perciò a questo livello il messaggio può essere gestito a seconda del parametro ad esso associato, potendo implementare in qualche modo un’esecuzione “su misura” della funzione di callback.
Test del subscriber
Siamo pronti per poter eseguire il nostro subscriber!
Ciò che ci aspettiamo è che vengano stampati allo stesso tempo il messaggio e l’argomento relativi alla callback innescata dall’arrivo di un messaggio dal singolo topic. L’output dovrebbe quindi essere di questo tipo:
[INFO] [***.***]: Ricevuto: Questo pubblica una stringa
Argomento passato da chatter0
[INFO] [***.***]: Ricevuto: 0.42
Argomento passato da chatter1
[INFO] [***.***]: Ricevuto: True
Argomento passato da chatter2
Per fare ciò dobbiamo eseguire il nostro nodo:
Terminale 3:
rosrun multiple_sub multiple_subscriber.py
Possiamo osservare come gli output si alternano ogni secondo a rotazione, ma questo è dovuto alla singola implementazione del publisher (che è possibile trovare all’interno del Rosject, vedi Risorse).
In ogni caso per ogni topic viene ricevuto, gestito e stampato un messaggio specifico relativo ad esso, e l’elaborazione del relativo parametro, con diverso risultato nonostante l’utilizzo della medesima funzione di callback.
0 Comments