¡Bienvenido! En esta web se encuentra todo el contenido visto y aprendido en mis
Prácticas Externas realizadas con la empresa JdeRobot durante el curso 2025-2026
en el Grado en Ingeniería de Robótica Software.
A continuación, se muestran todas las entradas correspondientes a los blogs de prácticas
realizados durante el transcurso de las mismas, cuyo contenido se divide en las
20 semanas que ha durado mi periodo de Prácticas Externas.
SEMANA 01: 22-09-2025 al 26-09-2025
Instalación de Docker en Ubuntu 24.04
En primer lugar, se abre una terminal por defecto en el directorio
/home/user, a través de la cual se irán ejecutando los siguientes
comandos:
PASO 1: Acceso al escritorio
cd Escritorio/
PASO 2: Clonación del repositorio de RoboticsAcademy
git clone --recurse-submodules https://github.com/JdeRobot/RoboticsAcademy.git
PASO 3: Acceso al repositorio de RoboticsAcademy
cd RoboticsAcademy/
PASO 4: Ejecución del script de preparación
Este script intenta configurar el entorno de desarrollo. Al ejecutar este script por
primera vez, aparecen varios errores, ya que faltan dependencias por instalar
(yarn y docker).
./scripts/develop_academy.sh
./scripts/develop_academy.sh: linea 146: yarn: orden no encontrada
./scripts/develop_academy.sh: linea 147: yarn: orden no encontrada
./scripts/develop_academy.sh: linea 166: docker: orden no encontrada
Cleaning up...
./scripts/develop_academy.sh: linea 28: docker: orden no encontrada
PASO 5: Ejecución de comandos de configuración
Todos los comandos que se ejecutan a continuación se encargan de actualizar los
repositorios de APT, instalar las herramientas necesarias (certificados y curl),
crear el directorio para las claves de Docker, descargar la clave GPG de
Docker, dar permisos de lectura a dicha clave, añadir el repositorio de Docker a
APT y volver a actualizar la lista de paquetes.
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
PASO 6: Instalación de Docker y todos sus componentes
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
PASO 7: Comprobación de la activación de Docker
sudo systemctl status docker
PASO 8: Instalación de Docker Compose
sudo apt install docker-compose
PASO 9: Verificación de la versión de Docker instalada
docker --version
PASO 10: Creación del grupo de usuarios de Docker
sudo groupadd docker
PASO 11: Adición del usuario actual al grupo Docker
sudo usermod -aG docker $USER
PASO 12: Cambio de grupo
newgrp docker
PASO 13: Reejecución del script de preparación
sudo ./scripts/develop_academy.sh
IMPORTANTE: Al ejecutar el comando con sudo, todo se ejecuta
correctamente.
Configuración y uso del Docker en Visual Studio Code
PASO 1: Apertura de RoboticsAcademy en Visual Studio Code
cd Escritorio/RoboticsAcademy/
code .
PASO 2: Instalación de las extensiones de Docker
Tras instalar ambas extensiones, es necesario reiniciar el equipo para que
Docker y Visual Studio Code se integren correctamente.
PASO 3: Bucle de trabajo a seguir en Visual Studio Code
- Hacer los cambios necesarios dentro del directorio
RoboticsInfrastructure/.
- Hacer commit y push de dichos cambios en una nueva rama (Publish Branch).
- Acceder al directorio RoboticsAcademy/scripts/RADI/.
cd scripts/RADI/
- Ejecutar el script build.sh dentro de la nueva rama.
./build.sh -i <branch_name>
- Volver al directorio principal.
cd ../..
- Cambiar la siguiente línea del fichero
compose_cfg/dev_humble_cpu.yaml.
# ANTES
robotics-academy:
image: jderobot/robotics-academy:latest
# DESPUÉS
robotics-academy:
image: jderobot/robotics-academy:test
- Ejecutar el script de preparación (sin sudo) para lanzar el Docker de
RoboticsAcademy con todos los cambios realizados.
./scripts/develop_academy.sh
- Acceder a la dirección web http://0.0.0.0:7164/ que aparece en la terminal al
ejecutar el comando anterior para poder entrar a Unibotics en local y verificar
que los cambios se han realizado correctamente.
IMPORTANTE: En el caso de que los cambios se hayan realizado
únicamente en el fichero database/universes.sql, sólo sería
necesario realizar el último de todos los pasos que componen este bucle de trabajo,
escrito a continuación.
./scripts/develop_academy.sh
Modificaciones necesarias para migrar de Gazebo 11 a Gazebo Harmonic
A continuación se enumeran todos y cada uno de los ficheros que se van a modificar
para poder llevar a cabo cada una de las tareas principales que se van a abordar
durante las Prácticas: La migración de escenarios, robots y otros elementos visuales
de Gazebo 11 a Gazebo Harmonic.
Todos estos ficheros se encuentran en el repositorio de GitHub
RoboticsInfrastructure,
que se encuentra a su vez dentro del repositorio de GitHub
RoboticsAcademy
(en ambos se trabajará desde la rama humble-devel).
FICHERO RoboticsInfrastructure/Launchers/<exercise_name>/spawn_robot.launch.py
# CAMBIAR EL NOMBRE DEL ROBOT
model_folder = <robot_name>
# CAMBIAR EL NOMBRE DEL FICHERO .YAML
bridge_params = os.path.join(
get_package_share_directory("custom_robots"), "params", "robot_params.yaml"
)
# AÑADIR / ELIMINAR LAS SIGUIENTES LÍNEAS SI EL ROBOT TIENE / NO TIENE CÁMARA
start_gazebo_ros_image_bridge_cmd = Node(
package="ros_gz_image",
executable="image_bridge",
arguments=["/<robot_name>/camera/image_raw"],
output="screen",
)
start_gazebo_ros_depth_bridge_cmd = Node(
package="ros_gz_image",
executable="image_bridge",
arguments=["/<robot_name>/camera/depth"],
output="screen",
)
ld.add_action(start_gazebo_ros_image_bridge_cmd)
ld.add_action(start_gazebo_ros_depth_bridge_cmd)
FICHERO RoboticsInfrastructure/CustomRobots/CMakeLists.txt
# AÑADIR LOS DIRECTORIOS CORRESPONDIENTES A LAS NUEVAS MIGRACIONES
install(
DIRECTORY
<exercise_name>/models
<robot_name>/models
<robot_name>/urdf
<robot_name>/params
DESTINATION share/${PROJECT_NAME})
FICHERO RoboticsInfrastructure/Launchers/<exercise_name>.launch.py
# CAMBIAR RUTAS Y NOMBRES DE LOS FICHEROS CARGADOS
robot_launch_dir = "/opt/jderobot/Launchers/<exercise_name>"
robot_model_dir = os.path.join(package_dir, "models/<robot_name>")
world_file_name = "<exercise_name>.world"
FICHERO RoboticsInfrastructure/Worlds/<exercise_name>.world
# MODIFICAR TODOS LOS APARTADOS CON EL FLAG INCLUDE
# GAZEBO 11
<include>
<uri>model://house_int2</uri>
<pose>0 0 0 0 0 0</pose>
# GAZEBO HARMONIC
<include>
<name>house_int2</name>
<uri>model://house_int2</uri>
<pose>0 0 0 0 0 0</pose>
</include>
FICHERO RoboticsInfrastructure/CustomRobots/<robot_name>/models/<robot_name>/model.sdf
# MODIFICAR TODOS LOS APARTADOS CON EL FLAG SENSOR Y EL FLAG PLUGIN
# GAZEBO 11
<sensor name='laser' type='ray'>
<ray>
<scan>
<horizontal>
<samples>180</samples>
<resolution>1.000000</resolution>
<min_angle>-1.570000</min_angle>
<max_angle>1.570000</max_angle>
</horizontal>
</scan>
<range>
<min>0.080000</min>
<max>10.000000</max>
<resolution>0.010000</resolution>
</range>
</ray>
<update_rate>20.000000</update_rate>
<always_on>1</always_on>
<visualize>1</visualize>
<plugin name="gazebo_ros_head_hokuyo_controller" filename="libgazebo_ros_ray_sensor.so">
<ros>
<remapping>~/out:=/roombaROS/laser/scan</remapping>
</ros>
<output_type>sensor_msgs/LaserScan</output_type>
<frameName>laser</frameName>
<update_rate>20.000000</update_rate>
</plugin>
</sensor>
# GAZEBO HARMONIC
<sensor name="hls_lfcd_lds" type="gpu_lidar">
<always_on>true</always_on>
<visualize>true</visualize>
<pose>-0.064 0 0.121 0 0 0</pose>
<update_rate>5</update_rate>
<topic>turtlebot3/laser/scan</topic>
<gz_frame_id>base_scan</gz_frame_id>
<lidar>
<scan>
<horizontal>
<samples>360</samples>
<resolution>1.000000</resolution>
<min_angle>0.000000</min_angle>
<max_angle>6.280000</max_angle>
</horizontal>
</scan>
<range>
<min>0.20000</min>
<max>3.5</max>
<resolution>0.015000</resolution>
</range>
</lidar>
</sensor>
<plugin filename="ignition-gazebo-odometry-publisher-system" name="ignition::gazebo::systems::OdometryPublisher">
<odom_frame>odom</odom_frame>
<robot_base_frame>base_footprint</robot_base_frame>
<odom_publish_frequency>50</odom_publish_frequency>
<odom_topic>turtlebot3/odom</odom_topic>
<dimensions>3</dimensions>
</plugin>
FICHERO RoboticsInfrastructure/CustomRobots/<robot_name>/params/robot_params.yaml
# AÑADIR LOS TOPICS DE TODOS LOS SENSORES QUE COMPONEN EL ROBOT
# gz topic published by DiffDrive plugin
- ros_topic_name: "<robot_name>/odom"
gz_topic_name: "<robot_name>/odom"
ros_type_name: "nav_msgs/msg/Odometry"
gz_type_name: "gz.msgs.Odometry"
direction: GZ_TO_ROS
# gz topic subscribed to by DiffDrive plugin
- ros_topic_name: "<robot_name>/cmd_vel"
gz_topic_name: "<robot_name>/cmd_vel"
ros_type_name: "geometry_msgs/msg/Twist"
gz_type_name: "gz.msgs.Twist"
direction: ROS_TO_GZ
# gz topic published by Sensors plugin (LIDAR)
- ros_topic_name: "<robot_name>/laser/scan"
gz_topic_name: "<robot_name>/laser/scan"
ros_type_name: "sensor_msgs/msg/LaserScan"
gz_type_name: "gz.msgs.LaserScan"
direction: GZ_TO_ROS
# gz topic published by Sensors plugin (Camera)
- ros_topic_name: "<robot_name>/camera/camera_info"
gz_topic_name: "<robot_name>/camera/camera_info"
ros_type_name: "sensor_msgs/msg/CameraInfo"
gz_type_name: "gz.msgs.CameraInfo"
direction: GZ_TO_ROS
FICHERO RoboticsInfrastructure/database/universes.sql
# MODIFICAR LOS PARÁMETROS DE LOS MUNDOS
# MUNDO NO MIGRADO (ANTES)
25 Vacuums House Markers /opt/jderobot/Launchers/marker_visual_loc.launch.py None ROS2 gazebo {1,-1.5,0.6,0,0,0}
# MUNDO MIGRADO (DESPUÉS)
25 Vacuums House Markers /opt/jderobot/Launchers/marker_visual_loc.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/marker_visual_loc.config"} ROS2 gz {1,-1.5,0.6,0,0,0}
Lanzamiento del RoboticsBackend en local
PASO 1
Para lanzar el RoboticsBackend y poder trabajar en Unibotics en local, se debe
ejecutar el siguiente comando en la terminal:
docker run --rm -it --device /dev/dri -p 6080:6080 -p 1108:1108 -p 7163:7163 jderobot/robotics-backend:latest
PASO 2
Se deja ejecutando el comando anterior en la terminal y se accede a la
página web de Unibotics.
PASO 3
Una vez dentro de Unibotics, se selecciona el ejercicio en el que se quiera
trabajar.
IMPORTANTE: Para que todo funcione correctamente, se debe
seleccionar la opción 'Local ROS2 (RoboticsBackend 4)', que aparece en la esquina
superior derecha al hacer clic en la foto de perfil.
PASO 4
Verificar que, tanto la simulación en Gazebo como la terminal, se han lanzado
correctamente.
Lanzamiento del RoboticsDatabase junto a RoboticsAcademy en local
PASO 1
Para poder lanzar RoboticsDatabase junto a RoboticsAcademy, se debe ejecutar el
siguiente comando en la terminal:
docker run --hostname my-postgres --name academy_db -d\
-e POSTGRES_DB=academy_db \
-e POSTGRES_USER=user-dev \
-e POSTGRES_PASSWORD=robotics-academy-dev \
-e POSTGRES_PORT=5432 \
-d -p 5432:5432 \
jderobot/robotics-database:latest
IMPORTANTE: Este comando se ejecuta ÚNICAMENTE la primera vez que
se lance el RoboticsDatabase junto a RoboticsAcademy.
PASO 2
Una vez ejecutado el comando anterior, ya no será necesario ejecutarlo
más veces, ya que lo que ha hecho este comando es crear un nuevo contenedor para
RoboticsDatabase, al cual se llamará con el flag --link cuando se vaya a lanzar
RoboticsAcademy. A continuación se muestran 3 formas diferentes de lanzar
RoboticsDatabase junto a RoboticsAcademy:
Lanzamiento de RoboticsDatabase + RoboticsAcademy (NVIDIA + GPU)
docker run --rm -it $(nvidia-smi >/dev/null 2>&1 && echo "--gpus all" || echo "") --device /dev/dri -p 6080:6080 -p 6081:6081 -p 1108:1108 -p 7163:7163 -p 7164:7164 --link academy_db jderobot/robotics-academy:latest
IMPORTANTE: Para que este comando funcione, es necesario tener
instalados los drivers de NVIDIA en Linux.
Lanzamiento de RoboticsDatabase + RoboticsAcademy (GPU)
docker run --rm -it --device /dev/dri -p 6080:6080 -p 6081:6081 -p 1108:1108 -p 7163:7163 -p 7164:7164 --link academy_db jderobot/robotics-academy:latest
Lanzamiento de RoboticsDatabase + RoboticsAcademy (CPU)
docker run --rm -it -p 6080:6080 -p 6081:6081 -p 1108:1108 -p 7163:7163 -p 7164:7164 --link academy_db jderobot/robotics-academy:latest
PASO 3
Por último, para comprobar que todos los Dockers que se van a utilizar se han
descargado y configurado correctamente, se debe ejecutar el siguiente comando
en la terminal:
sudo docker images
Cuyo resultado debe ser el siguiente:
REPOSITORY TAG IMAGE ID CREATED SIZE
jderobot/robotics-backend latest 0e2a10ccfaf4 5 days ago 27.2GB
jderobot/robotics-academy latest 1c67a50c79c2 13 days ago 28.5GB
jderobot/robotics-database latest 3a1d0407347e 13 days ago 483MB
SEMANA 02: 29-09-2025 al 03-10-2025
Ejercicio de calentamiento: Cambiar el mundo a un ejercicio
Para ir familiarizándonos con el software de RoboticsInfrastructure, se me ha
pedido como primer ejercicio cambiar el mundo de Gazebo de uno de los ejercicios
que ya se haya migrado a Gazebo Harmonic.
En primer lugar, he accedido al fichero
RoboticsInfrastructure/database/universes.sql para localizar
aquellos mundos ya migrados a Gazebo Harmonic.
IMPORTANTE: La forma más sencilla de identificar los mundos migrados
a Gazebo Harmonic, es mirando si en su columna type aparece escrito
gazebo o gz. En caso de que aparezca escrito
gazebo, significa que ese mundo todavía se encuentra en Gazebo 11
y no se ha migrado. Pero si aparece escrito gz, significa que ese
mundo ya se ha migrado a Gazebo Harmonic.
A continuación se listan todos los mundos que tienen escrito gz
en su columna type, y que podrían utilizarse para llevar a cabo
este ejercicio:
12 Laser Mapping Warehouse /opt/jderobot/Launchers/laser_mapping.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/laser_mapping.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
25 Vacuums House Markers /opt/jderobot/Launchers/marker_visual_loc.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/marker_visual_loc.config"} ROS2 gz {1,-1.5,0.6,0,0,0}
31 Rescue People Harmonic /opt/jderobot/Launchers/rescue_people.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/rescue_people.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
32 Follow Road Harmonic /opt/jderobot/Launchers/follow_road.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/follow_road.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
33 Small Laser Mapping Warehouse /opt/jderobot/Launchers/small_laser_mapping.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/small_laser_mapping.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
34 Pick And Place Arm /home/dev_ws/src/IndustrialRobots/ros2_SimRealRobotControl/ros2srrc_launch/moveit2/moveit2.launch.py None ROS2 gazebo {0.0,0.0,0.0,0.0,0.0,0.0}
35 Car Junction /opt/jderobot/Launchers/car_junction.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/car_junction.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
36 Drone Gymkhana Harmonic /opt/jderobot/Launchers/drone_gymkhana.launch.py None ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
37 Tower Inspection Harmonic /opt/jderobot/Launchers/power_tower_inspection.launch.py None ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
En mi caso, he seleccionado los mundos correspondientes a los ejercicios de
Laser Mapping (número 12) y Marker Based Visual Loc
(número 25). El mundo del Laser Mapping es un almacén tipo Amazon,
mientras que el mundo del Marker Based Visual Loc es una casa de
dos plantas.
El resultado final de este ejercicio visualizará el almacén del ejercicio
Laser Mapping en la ventana de Gazebo del ejercicio
Marker Based Visual Loc.
A continuación se muestra cómo se ve inicialmente el ejercicio
Marker Based Visual Loc al lanzar el Docker de RoboticsAcademy
antes de realizar cualquier cambio en el código:
El único cambio que he realizado ha sido en el fichero
RoboticsInfrastructure/Launchers/marker_visual_loc.launch.py
en la siguiente línea:
# ANTES (MUNDO ORIGINAL)
world_file_name = "marker_visual_loc.world"
# DESPUÉS (MUNDO NUEVO)
world_file_name = "laser_mapping.world"
Una vez realizado este cambio, he hecho commit y push en una nueva rama que he creado
y publicado llamada test-aleon2020. Es importante hacer esto
siempre para evitar así cualquier tipo de conflicto con la rama principal.
Como los cambios se han realizado en un fichero que se encuentra dentro de
RoboticsInfrastructure, es obligatorio generar un nuevo RADI. Para ello, se deben
ejecutar los siguientes comandos en la terminal:
cd scripts/RADI/
./build.sh -i test-aleon2020
IMPORTANTE: Si es la primera vez que se ejecuta este script, el
tiempo que tardará en ejecutarse por completo será considerablemente largo, ya que
debe configurar todo el entorno. Si es la primera vez que se ejecuta tardará unos
35-45 minutos, de lo contrario, tardará unos 2-3 minutos.
Una vez finalizada la ejecución del script build.sh, se debe
regresar al repositorio principal:
cd ../..
Pero antes de ejecutar el script develop_academy.sh, hay que
modificar la siguiente línea del fichero
RoboticsAcademy/compose_cfg/dev_humble_cpu.yaml:
# ANTES
robotics-academy:
image: jderobot/robotics-academy:latest
# DESPUÉS
robotics-academy:
image: jderobot/robotics-academy:test
Con este cambio ya realizado, ya se puede lanzar el script
develop_academy.sh:
./scripts/develop_academy.sh
Y por último, sólo quedaría acceder a la dirección web `http://0.0.0.0:7164/` que
aparece en la terminal al ejecutar el comando anterior para poder entrar a Unibotics
en local y verificar que los cambios se han realizado correctamente.
A continuación se muestra cómo se ve el ejercicio
Marker Based Visual Loc al lanzar el Docker de RoboticsAcademy
con todos estos cambios realizados en el código:
Migración del ejercicio Obstacle Avoidance a Gazebo Harmonic
Una vez realizado este primer ejercicio de calentamiento para irme familiarizando
con el código de RoboticsInfrastructure, se me ha pedido realizar la migración
completa de Gazebo 11 a Gazebo Harmonic del ejercicio
Obstacle Avoidance, que introduce de forma práctica la navegación
local mediante el uso de campos de fuerza virtuales (VFF, Virtual Force Fields).
ENLACE AL ENUNCIADO DEL EJERCICIO: https://jderobot.github.io/RoboticsAcademy/exercises/AutonomousCars/obstacle_avoidance
A continuación, se encuentran todos los ficheros que se han modificado y/o creado
(y de qué forma) para poder llevar a cabo la migración completa de este ejercicio
de Gazebo 11 a Gazebo Harmonic:
FICHERO RoboticsInfrastructure/CustomRobots/f1/models/f1_result_laser_no_cam/model.sdf
En este fichero se han modificado las partes correspondientes a las etiquetas
<plugin> y <sensor>, donde el plugin pasa de estar declarado dentro
del sensor a integrarse en él. Además, es importante añadir al final de la nueva
versión los plugins correspondientes al diff-drive-system y al
odometry-publisher-system:
# GAZEBO 11
<sensor name='laser' type='ray'>
<ray>
<scan>
<horizontal>
<samples>180</samples>
<resolution>1.000000</resolution>
<min_angle>-1.570000</min_angle>
<max_angle>1.570000</max_angle>
</horizontal>
</scan>
<range>
<min>0.080000</min>
<max>10.000000</max>
<resolution>0.010000</resolution>
</range>
</ray>
<update_rate>20.000000</update_rate>
<plugin name="gazebo_ros_head_hokuyo_controller" filename="libgazebo_ros_ray_sensor.so">
<ros>
<namespace>/f1</namespace>
<remapping>~/out:=laser/scan</remapping>
</ros>
<output_type>sensor_msgs/LaserScan</output_type>
<frame_name>base_scan</frame_name>
</plugin>
<always_on>1</always_on>
<visualize>1</visualize>
</sensor>
# ESTE PLUGIN SE INTEGRA DENTRO DE <SENSOR> AL PASAR A GAZEBO HARMONIC
<plugin name="object_controller" filename="libgazebo_ros_planar_move.so">
<commandTopic>F1ROS/cmd_vel</commandTopic>
<odometryTopic>F1ROS/odom</odometryTopic>
<odometryFrame>odom</odometryFrame>
<odometryRate>20.0</odometryRate>
<robotBaseFrame>xf1</robotBaseFrame>
</plugin>
# GAZEBO HARMONIC
<sensor name="laser" type="gpu_lidar">
<always_on>1</always_on>
<visualize>1</visualize>
<pose>0.500000 0.000000 0.072000 0.000000 0.000000 0.00000</pose>
<update_rate>20.000000</update_rate>
<topic>f1/laser/scan</topic>
<gz_frame_id>base_scan</gz_frame_id>
<lidar>
<scan>
<horizontal>
<samples>180</samples>
<resolution>1.000000</resolution>
<min_angle>-1.570000</min_angle>
<max_angle>1.570000</max_angle>
</horizontal>
</scan>
<range>
<min>0.080000</min>
<max>10.000000</max>
<resolution>0.010000</resolution>
</range>
</lidar>
</sensor>
# AÑADIR ESTE PLUGIN AL FINAL DEL FICHERO
<plugin filename="gz-sim-diff-drive-system" name="gz::sim::systems::DiffDrive">
<!-- wheels -->
<left_joint>wheel_left_joint</left_joint>
<right_joint>wheel_right_joint</right_joint>
<!-- kinematics -->
<wheel_separation>0.287</wheel_separation>
<wheel_radius>0.033</wheel_radius>
<!-- limits -->
<max_linear_acceleration>1.0</max_linear_acceleration>
<topic>F1ROS/cmd_vel</topic>
<frame_id>odom</frame_id>
<!-- <tf_topic>/tf</tf_topic> -->
<odom_publisher_frequency>20.0</odom_publisher_frequency>
<child_frame_id>xf1</child_frame_id>
</plugin>
# AÑADIR ESTE PLUGIN AL FINAL DEL FICHERO
<plugin filename="ignition-gazebo-odometry-publisher-system" name="ignition::gazebo::systems::OdometryPublisher">
<odom_frame>odom</odom_frame>
<robot_base_frame>xf1</robot_base_frame>
<odom_publish_frequency>20.0</odom_publish_frequency>
<odom_topic>F1ROS/odom</odom_topic>
<dimensions>3</dimensions>
</plugin>
FICHERO RoboticsInfrastructure/CustomRobots/f1/params/f1_result_laser_no_cam.yaml
Este fichero se crea de cero en la ruta especificada, aunque se puede coger
cualquier fichero del tipo robot_params.yaml como referencia.
En este caso, sólo se añaden los topics correspondientes al publicador y al
subscriptor del plugin del diff-drive-system y aquellos relativos al publicador
del plugin del láser:
# gz topic published by DiffDrive plugin
- ros_topic_name: "F1ROS/odom"
gz_topic_name: "F1ROS/odom"
ros_type_name: "nav_msgs/msg/Odometry"
gz_type_name: "gz.msgs.Odometry"
direction: GZ_TO_ROS
# gz topic subscribed to by DiffDrive plugin
- ros_topic_name: "F1ROS/cmd_vel"
gz_topic_name: "F1ROS/cmd_vel"
ros_type_name: "geometry_msgs/msg/Twist"
gz_type_name: "gz.msgs.Twist"
direction: ROS_TO_GZ
# gz topic published by Sensors plugin (LIDAR)
- ros_topic_name: "F1ROS/laser/scan"
gz_topic_name: "F1ROS/laser/scan"
ros_type_name: "sensor_msgs/msg/LaserScan"
gz_type_name: "gz.msgs.LaserScan"
direction: GZ_TO_ROS
FICHERO RoboticsInfrastructure/CustomRobots/CMakeLists.txt
En este caso, la única modificación realizada en este fichero es la
adición de la línea f1/params para que el fichero que se acaba de
crear (f1_result_laser_no_cam.yaml) se tenga en cuenta a la hora de
lanzar el Docker:
# GAZEBO 11
install(
DIRECTORY
...
# F1
f1/models
f1/launch
f1/worlds
...
DESTINATION share/${PROJECT_NAME})
# GAZEBO HARMONIC
install(
DIRECTORY
...
# F1
f1/models
f1/launch
f1/worlds
f1/params
...
DESTINATION share/${PROJECT_NAME})
FICHERO RoboticsInfrastructure/Launchers/obstacle_avoidance/spawn_robot.launch.py
Una vez creado el directorio obstacle_avoidance/, y a su vez dentro
de él el fichero spawn_robot.launch.py, lo único que habría que
hacer es coger cualquier fichero con el mismo nombre de otro ejercicio que ya esté
migrado a Gazebo Harmonic, copiar su contenido y sólamente habría que comentar todo
lo relativo a las variables start_gazebo_ros_image_bridge_cmd y
start_gazebo_ros_depth_bridge_cmd, y lo más importante, modificar
el nombre del fichero que se le pasa como argumento a bridge_params (en este caso,
f1_renault_laser_no_cam.yaml):
# GAZEBO 11
bridge_params = os.path.join(
get_package_share_directory("custom_robots"), "params", "robot_params.yaml"
)
# GAZEBO HARMONIC
bridge_params = os.path.join(
get_package_share_directory("custom_robots"), "params", "f1_renault_laser_no_cam.yaml"
)
FICHERO RoboticsInfrastructure/Launchers/visualization/simple_circuit_obstacles_followingcam.config
El contenido de este fichero es idéntico al del resto de ficheros con el mismo
formato de nombre (<universe_name>.config), por lo que lo único que habría que
hacer es crear este nuevo fichero y rellenar su contenido con un simple Ctrl+C Ctrl+V
de otro fichero que se encuentre en el mismo directorio con el mismo formato de
nombre.
<?xml version="1.0"?>
<!-- Quick start dialog -->
<dialog name="quick_start" show_again="false"/>
<!-- Window -->
<window>
<width>1024</width>
<height>768</height>
<style material_theme="Light" material_primary="DeepOrange" material_accent="LightBlue" toolbar_color_light="#f3f3f3" toolbar_text_color_light="#111111" toolbar_color_dark="#414141" toolbar_text_color_dark="#f3f3f3" plugin_toolbar_color_light="#bbdefb" plugin_toolbar_text_color_light="#111111" plugin_toolbar_color_dark="#607d8b" plugin_toolbar_text_color_dark="#eeeeee"/>
<menus>
<drawer visible="false">
</drawer>
<plugins visible="false">
</plugins>
</menus>
<dialog_on_exit>false</dialog_on_exit>
</window>
<!-- GUI plugins -->
<!-- 3D scene -->
<plugin filename="MinimalScene" name="3D View">
<gz-gui>
<title>3D View</title>
<property type="bool" key="showTitleBar">false</property>
<property type="string" key="state">docked</property>
</gz-gui>
<engine>ogre2</engine>
<scene>scene</scene>
<ambient_light>0.4 0.4 0.4</ambient_light>
<background_color>0.8 0.8 0.8</background_color>
<camera_pose>-6 0 6 0 0.5 0</camera_pose>
</plugin>
<plugin filename="CameraTracking" name="Camera tracking">
<gz-gui>
<property key="resizable" type="bool">false</property>
<property key="width" type="double">5</property>
<property key="height" type="double">5</property>
<property key="state" type="string">floating</property>
<property key="showTitleBar" type="bool">false</property>
</gz-gui>
<follow_target>drone0</follow_target>
<follow_offset>-2 0 2</follow_offset>
<follow_pgain>0.4</follow_pgain>
</plugin>
<!-- Plugins that add functionality to the scene -->
<plugin filename="GzSceneManager" name="Scene Manager">
<gz-gui>
<property key="resizable" type="bool">false</property>
<property key="width" type="double">5</property>
<property key="height" type="double">5</property>
<property key="state" type="string">floating</property>
<property key="showTitleBar" type="bool">false</property>
</gz-gui>
</plugin>
<plugin filename="InteractiveViewControl" name="Interactive view control">
<gz-gui>
<property key="resizable" type="bool">false</property>
<property key="width" type="double">5</property>
<property key="height" type="double">5</property>
<property key="state" type="string">floating</property>
<property key="showTitleBar" type="bool">false</property>
</gz-gui>
</plugin>
<plugin filename="WorldStats" name="World stats">
<gz-gui>
<title>World stats</title>
<property type="bool" key="showTitleBar">false</property>
<property type="bool" key="resizable">false</property>
<property type="double" key="height">110</property>
<property type="double" key="width">290</property>
<property type="double" key="z">1</property>
<property type="string" key="state">floating</property>
<anchors target="3D View">
<line own="right" target="right"/>
<line own="bottom" target="bottom"/>
</anchors>
</gz-gui>
<sim_time>true</sim_time>
<real_time>true</real_time>
<real_time_factor>true</real_time_factor>
<iterations>true</iterations>
<topic>/world/world_demo/stats</topic>
</plugin>
FICHERO RoboticsInfrastructure/Launchers/simple_circuit_obstacles_followingcam.launch.py
Para este fichero, lo único que habría que hacer es un Ctrl+C Ctrl+V de
cualquier fichero con el mismo formato de nombre que ya haya sido migrado a Gazebo
Harmonic y modificar únicamente las líneas correspondientes a las
variables robot_launch_dir y world_file_name,
correspondientes a las rutas en las que se encuentran el directorio que almacena el
fichero spawn_robot.launch.py y el fichero del mundo que utiliza
este ejercicio.
robot_launch_dir = "/opt/jderobot/Launchers/obstacle_avoidance"
world_file_name = "simple_circuit_obstacles_followingcam.world"
IMPORTANTE: En caso de que no se haya creado dentro del directorio
obstacle_avoidance/ el fichero
robot_state_publisher.launch.py, es obligatorio comentar
y/o eliminar del código todo lo relacionado con la variable
robot_state_publisher_cmd.
FICHERO RoboticsInfrastructure/Worlds/simple_circuit_obstacles_followingcam.world
En este fichero, lo único que habría que realizar es un Ctrl+C Ctrl+V de
cualquier fichero con el mismo formato de nombre que ya haya sido migrado a Gazebo
Harmonic y sustituir todas aquellos flags <include> de la versión antigua por
aquellos que aparezcan en la versión nueva.
<?xml version="1.0" ?>
<sdf version="1.9">
<world name="default">
<plugin
filename="gz-sim-physics-system"
name="gz::sim::systems::Physics">
</plugin>
<plugin
filename="gz-sim-scene-broadcaster-system"
name="gz::sim::systems::SceneBroadcaster">
</plugin>
<plugin
filename="gz-sim-sensors-system"
name="gz::sim::systems::Sensors">
<render_engine>ogre2</render_engine>
</plugin>
<scene>
<shadows>false</shadows>
</scene>
<light type="directional" name="sun">
<!-- true -->
<pose>0 0 20 -1.3 0 0.5</pose>
<diffuse>0.8 0.8 0.8 1</diffuse>
<specular>0.01 0.01 0.01 1</specular>
<intensity>2</intensity>
<visualize>false</visualize>
</light>
<light type="point" name="point_light">
<pose>0.73 0.09 8.77 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.01 0.01 0.01 1</specular>
<attenuation>
<range>10</range>
<linear>0.5</linear>
<constant>0.8</constant>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>false</cast_shadows>
<visualize>false</visualize>
</light>
<light type="point" name="point_light_02">
<pose>0.13 0.46 11.60 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.01 0.01 0.01 1</specular>
<attenuation>
<range>10</range>
<linear>0.2</linear>
<constant>0.5</constant>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>false</cast_shadows>
<visualize>false</visualize>
</light>
<light type="point" name="point_light_03">
<pose>4.27 -1.27 11.21 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>0.01 0.01 0.01 1</specular>
<attenuation>
<range>10</range>
<linear>0.5</linear>
<constant>0.8</constant>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>false</cast_shadows>
<visualize>false</visualize>
</light>
<light type="point" name="point_light_04">
<pose>-0.31 -3.78 8.61 0 0 0</pose>
<diffuse>1 1 1 1</diffuse>
<specular>.01 .01 .01 1</specular>
<attenuation>
<range>10</range>
<linear>0.5</linear>
<constant>0.8</constant>
<quadratic>0.001</quadratic>
</attenuation>
<cast_shadows>false</cast_shadows>
<visualize>false</visualize>
</light>
<include>
<uri>model://simple_circuit</uri>
<pose>-53.46 11.50 0 0 0 0</pose>
</include>
<include>
<uri>model://f1_renault_laser_no_cam</uri>
<pose>0.04 0.68 0 0 0 -1.57</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_1</name>
<pose>-0.1 -33 0 0 0 0</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_2</name>
<pose>-7 -40 0 0 0 -1.67</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_3</name>
<pose>-13.2 -18.8 0 0 0 -3</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_4</name>
<pose>-40 -11.5 0 0 0 -1.57</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_5</name>
<pose>-66.83 -34.15 0 0 0 -1.03</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_6</name>
<pose>-70.8 -34.2 0 0 0 -1.33</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_7</name>
<pose>-103 14.6 0 0 0 2.47</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_8</name>
<pose>-52.76 42.3 0 0 0 2.15</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_9</name>
<pose>-33.4 57.3 0 0 0 0</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_10</name>
<pose>-3.5 59 0 0 0 0.785</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_11</name>
<pose>1 26.2 0 0 0 0</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_11</name>
<pose>1 26.2 0 0 0 0</pose>
</include>
<include>
<uri>model://f1_dummy</uri>
<name>f1_dummy_12</name>
<pose>-1 24.5 0 0 0 0</pose>
</include>
</world>
</sdf>
FICHERO RoboticsInfrastructure/database/universes.sql
Este es uno de los cambios más sencillos de realizar en todo el proceso de migración.
Lo único que habría que hacer es identificar el ejercicio que se quiere migrar de
Gazebo 11 a Gazebo Harmonic (en este caso, Obstacle Avoidance) y tener en cuenta lo
siguiente: Cambiar el valor de la columna type de
gazebo a gz, y el campo de la tercera columna,
en el que inicialmente aparece None, sustituirlo por la ruta al fichero
simple_circuit_obstacles_followingcam.config creado anteriormente:
# GAZEBO 11
19 Obstacle Avoidance Default /opt/jderobot/Launchers/simple_circuit_obstacles_followingcam.launch.py None ROS2 gazebo {0.0,0.0,0.0,0.0,0.0,0.0}
# GAZEBO HARMONIC
19 Obstacle Avoidance Default /opt/jderobot/Launchers/simple_circuit_obstacles_followingcam.launch.py {"gzsim":"/opt/jderobot/Launchers/visualization/simple_circuit_obstacles_followingcam.config"} ROS2 gz {0.0,0.0,0.0,0.0,0.0,0.0}
Una vez realizados todos estos cambios en todos los ficheros mencionados,
he hecho commit y push en una nueva rama que he creado y publicado llamada
obstacle-avoidance-harmonic. Es importante hacer esto siempre para
así evitar cualquier tipo de conflicto con la rama principal.
Como todos los cambios se han realizado en ficheros que se encuentran dentro de
RoboticsInfrastructure, es obligatorio generar un nuevo RADI. Para ello, se deben
ejecutar los siguientes comandos en la terminal:
cd scripts/RADI/
./build.sh -i obstacle-avoidance-harmonic
Una vez finalizada la ejecución del script build.sh, se debe
regresar al repositorio principal:
cd ../..
Pero antes de ejecutar el script develop_academy.sh, hay que
modificar la siguiente línea del fichero
RoboticsAcademy/compose_cfg/dev_humble_cpu.yaml:
# ANTES
robotics-academy:
image: jderobot/robotics-academy:latest
# DESPUÉS
robotics-academy:
image: jderobot/robotics-academy:test
Con este cambio ya realizado, ya se puede lanzar el script
develop_academy.sh:
./scripts/develop_academy.sh
Y por último, sólo quedaría acceder a la dirección web `http://0.0.0.0:7164/` que
aparece en la terminal al ejecutar el comando anterior para poder entrar a Unibotics
en local y verificar que los cambios se han realizado correctamente.
A continuación se muestra cómo se ve el ejercicio Obstacle Avoidance
al lanzar el Docker de RoboticsAcademy con todos estos cambios realizados:
IMAGEN UNIBOTICS GAZEBO OBSTACLE AVOIDANCE
Además, para verificar que tanto el escenario como el coche han sido migrados
correctamente, se muestra una pequeña animación del coche moviéndose en línea
recta para verificar que todo el proceso se ha realizado correctamente:
VÍDEO / GIF COCHE MOVIÉNDOSE POR EL ESCENARIO