Clase 06
Semana 7 - 28/04/2025
Programación Orientada a Objetos
Código publisher y suscriber
rclpy
: ParámetrosPermiten configurar nodos sin tener que reprogramarlos
Se crean y destruyen con el nodo
Consisten en
rclpy
: ParámetrosSe declaran todos al inicio, antes de hacer uso
self.declare_parameter('<nombre>', <valor>)
self.declare_parameter('<nombre>', <valor>, <desc>)
El tipo es inferido a través del valor
rclpy
: ParámetrosPara obtener el valor
param = self.get_parameter('<nombre>')
valor = param.value
Establecer el valor (desde el nodo)
nuevo_valor = rclpy.parameter.Parameter(<nombre>, <tipo>, valor>)
self.set_parameters([ nuevo_valor ])
rclpy
: ParámetrosExiste un callback para cuando se modifica algún parámetro
# Dentro del constructor de la clase
self.handler = ParameterEventHandler(self)
self.callback_handle = self.handler.add_parameter_callback(
parameter_name = "<nombre_parametro>",
node_name = "<nombre_nodo>",
callback = <callback>,
)
El callback recibe el parámetro modificado
def callback(self, p: rclpy.parameter.Parameter) -> None:
...
Propiedades que ROS permite reconfigurar
$ ros2 run <nombre_paquete> <nombre_ejecutable> --ros-args ...
-r
o --remap
$ ros2 run ... --ros-args -r __node:=<nuevo_nombre_nodo>
$ ros2 run ... --ros-args -r __ns:=/<nombre_namespace>
$ ros2 run ... --ros-args -r <topic>:=<nuevo_nombre_topic>
Nivel de log: --log-level
$ ros2 run ... --ros-args --log-level <info|debug|warn|error>
Para el caso de parámetros:
-p
$ ros2 run <nombre_paquete> <nombre_ejecutable>
--ros-args -p <nombre_parametro>:=<valor>
Cuando el nodo se encuentra en ejecución:
$ ros2 param set ...
ros2launch
Herramienta que permite la ejecución de múltiples nodos con un simple comando:
ros2 launch ...
Tareas más comunes:
ros2launch
Por convención se ubican en la carpeta
launch
dentro del paquete
Formatos:
- XML:
nombre_archivo.xml
- YAML:
nombre_archivo.yaml
- Python:
nombre_archivo.launch.py
⬅️
Es necesario adecuar el archivo
setup.py
:
from setuptools import setup
import os
from glob import glob
package_name = 'nombre_paquete'
setup(
# Otros parámetros ...
data_files=[
# ... Otros archivos
# Incluir todos los archivos de la carpeta launch
(os.path.join('share', package_name, 'launch'), glob('launch/*'))
],
# El resto de la configuración ...
)
Se recomienda agregar ros2launch
como dependencia de ejecución:
<exec_depend>ros2launch</exec_depend>
Se debe implementar la función
generate_launch_description()
que devuelve
launch.LaunchDescription()
Esta función será utilizada por el comando:
$ ros2 launch <nombre_paquete> <nombre_archivo_launch>
Importar las librerías
launch
ylaunch_ros
Formas de agregar acciones (ejemplo con nodo)
def generate_launch_description():
return LaunchDescription([
Node(
package = '<nombre_paquete>',
executable = '<nombre_ejecutable>',
name = '<nombre_nodo>',
),
])
Actions: Ejecutar un nodo
from launch_ros.actions import Node
...
return LaunchDescription([
Node(
package = '<nombre_paquete>',
executable = '<nombre_ejecutable>',
name = '<nombre_nodo>',
namespace = '<nombre_namespace>',
parameters = [ # Pueden ser archivos
{'<nombre_parametro>': <valor>, .. }
],
remappings = [
('<nombre_topic>', '<nuevo_nombre>'),
],
output = '<screen|log|both>',
ros_arguments = [...], # Listado de argumentos de ejecución (nivel de log, etc)
arguments = [...], # Listado de argumentos para el nodo
),
])
Substitutions: Parámetros para cambiar valores en el launch
...
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
def generate_launch_description():
return LaunchDescription([
DeclareLaunchArgument(
'<nombre_parametro>', default_value=<valor>
),
Node(
package = '<nombre_paquete>',
executable = '<nombre_ejecutable>',
name = '<nombre_nodo>',
parameters=[{
'<parametro_del_nodo>': LaunchConfiguration('<nombre_parametro>'),
}]
),
])
Conditions: Mecanismos para cambiar el comportamiento del launch
...
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, EqualsSubstitution
def generate_launch_description():
return LaunchDescription([
DeclareLaunchArgument(
'ejecutar_nodo', default_value='true'
),
Node(
package = '<nombre_paquete>',
executable = '<nombre_ejecutable>',
name = '<nombre_nodo>',
condition=IfCondition(
EqualsSubstitution(LaunchConfiguration('ejecutar_nodo'), 'true')
),
),
])
Reutilización: Incluir otros launch
...
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
return LaunchDescription([
IncludeLaunchDescription(
PythonLaunchDescriptionSource([
FindPackageShare('<nombre_paquete>'), '/launch', '/<nombre_archivo_launch>'
])
)
...
])
Por defecto los mensajes de log se escriben en:
- La consola
- El archivo de log en el disco
- El topic
\rosout
Pueden activarse y desactivarse individualmente
Escala de gravedad (
severity level
)
En orden descendente:
FATAL
ERROR
WARN
INFO
DEBUG
rclpy
Obtener el logger de una clase nodo:
<nodo>.get_logger().{debug,info,warning,error,fatal}('<mensaje_de_log>')
Opciones para configurar el comportamiento:
once
: Loggear solo la primera vezskip_first
: No loggear la primera vez, si las siguientesthrottle_duration_sec
: Cantidad de veces que se puede enviar el mensaje por segundo
Uso de parámetros y archivos launch
Robótica - TUAR - FICH - UNL