Post

Problemas entorno, creación de robot con láser y cámara y programa robótico externo

Problemas entorno

La semana anterior, llegué a la conclusión de descargar O3DE 23.10.3 y ROS2 Humble ya que era un entorno de trabajo que sabía que funcionaba.

Durante los primeros días de la sexta semana he estado teniendo problemas con la instalación del entorno, debido a que de primera intente hacerlo por docker, pero tuve muchos problemas y decidí hacer todo en nativo instalando ubuntu 22.04.

También, tuve problemas a la hora de montar el entorno O3DE, debido a que al ser una versión antigua, he tenido que instalarlo desde código fuente y compilarlo.

Mientras he tenido estos problemas y durante las esperas de carga de compilación he estado estudiando los distintos componentes que posee la gem de ROS2 de O3DE.

Creación de robot con láser y cámara

Una vez ya conseguido por fin que el entorno O3DE con ROS2 funcione correctamente, me puse manos a la obra a realizar el robot móvil con láser(y luego de implementar ese, incorporar la cámara que se pidió).

Para construir el robot me base en los modelos ya cargados de rosbot xl de la plantilla por defecto de warehouse.

Modelo RobotXl

Los problemas más grande que tuve con la creación del robot fueron:

  • Funcionamiento motriz: La ruedas o no funcionaban o giraban en una orientación distinta.

  • Funcionamiento del láser: El láser funcionaba y se desplegaba pero incorrectamente, se desplegaba como un rastro en vez analizar el alrededor del escenario.

Estos problemas fueron principalmente, debido a la cantidad de detalles y componentes importantes que deben estar configurados de cierta manera para que funcionara correctamente.

El problema de las ruedas fue debido al componente PhysX Hinge Joint, un componente básico para el funcionamiento de las ruedas del robot.

Componente O3DE PhysX Hinge Joint

En este componente se me olvido activar Motor, que es lo que hacía que las ruedas no funcionaran y se me olvido quitar el limitador y rotar el z en local rotation, provocando que las ruedas funcionaran mal.

El problema del láser era debido a que la parte del robot que hacía de laser tenía un collider, al meter el componente láser(en otra entidad hija), el láser se quedaba atrapado dentro y no se desplegaba bien, una vez quite el collider, el láser se desplegaba correctamente.

Una vez terminado todo inserte también cámara y no hubo problemas en la instalación de la misma.

Aqui un video del funcionamiento del movimiento del robot y el laser(aun no había metido cámara, ya que para comprobar que funcionaba la cámara lo comprobaría en la siguiente tarea):

Para mover el robot, utilice el component input y use un script predeterminado de la plantilla básica warehouse para poder mover el robot con las flechas del teclado.

Programa robótico externo

Cuando ya cumpli la anterior tarea, ahora debía realizar un programa externo en cualquier lenguaje(en mi caso, python) que debía comunicarse a traves de los ros topic y debía cumplir lo siguiente:

  • Mover el robot dando vueltas
  • Mostrar por consola la odometría(posición del robot respecto al spawn)
  • Mostrar por consola la distancia del laser central
  • Mostrar la cámara, tanto en color como en profundidad

Para realizar el tema de mostrar imagenes use opencv, ya que es sencillo de manejar el tema de ventanas gráficas y tiene compatibilidad con ROS usando la librería cvbridge que se encarga de traducir las imagenes que captura ROS a formato que soporte opencv.

Para poder realizar el programa en python me estuve ayudando con la página de github ros2 common interfaces, que muestra casos de ejemplo y como está estructurado varias cosas en ROS.

Una vez terminado el programa el código queda así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import cv2
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
from sensor_msgs.msg import LaserScan, Image
from cv_bridge import CvBridge
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy

class RobotController(Node):
    #Publicador cmd_vel
    #Suscriptor odom
    #Suscriptor scanner(solo primera cordenada central)
    #Suscriptor camera_image_color y camera_image_depth

    def __init__(self):
        super().__init__("robot_controller")

        sensor_qos = QoSProfile(
            depth=10,
            reliability=ReliabilityPolicy.BEST_EFFORT
        )

        self.cmd_vel_pub=self.create_publisher(Twist,"/cmd_vel", sensor_qos)

        self.odom_sub=self.create_subscription(Odometry,"/odom", self.odom_callback, sensor_qos)

        self.laser_sub=self.create_subscription(LaserScan,"/scan", self.laser_callback, sensor_qos)

        self.camera_color_sub=self.create_subscription(Image,"/camera_image_color", self.camera_color_callback, sensor_qos)

        self.camera_depth_sub=self.create_subscription(Image,"/camera_image_depth", self.camera_depth_callback, sensor_qos)

        self.bridge = CvBridge()

        self.movement_timer = self.create_timer(0.1, self.continuous_movement)

    def odom_callback(self, msg):
        x=msg.pose.pose.position.x
        y=msg.pose.pose.position.y
        self.get_logger().info(f"Odometria: x={x:.2f}, y={y:.2f}")

    def laser_callback(self, msg):
        central_index=len(msg.ranges)//2
        central_distance=msg.ranges[central_index]
        self.get_logger().info(f"Ecaner posición central: dist={central_distance:.2f}")

    def camera_color_callback(self, msg):
        frame= self.bridge.imgmsg_to_cv2(msg, desired_encoding="bgr8")
        cv2.imshow("Camera color", frame)
        cv2.waitKey(1)

    def camera_depth_callback(self, msg):
        frame= self.bridge.imgmsg_to_cv2(msg, desired_encoding="32FC1")
        cv2.imshow("Camera depth", frame)
        cv2.waitKey(1)

    def move(self, linear, angular):
        msg=Twist()
        msg.linear.x=linear
        msg.angular.z=angular
        self.cmd_vel_pub.publish(msg)

    def continuous_movement(self):
        self.move(0.2,0.2)

def main(args=None):
    print("Programa robótico iniciado", flush=True) 
    
    try:
        rclpy.init(args=args)
        robot_program = RobotController()
        rclpy.spin(robot_program)
    except KeyboardInterrupt:
        print("\nInterrupción por teclado")
    except Exception as e:
        print(f"Error: {e}")
    finally:
        try:
            robot_program.destroy_node()
            rclpy.shutdown()
            cv2.destroyAllWindows()
        except:
            pass

if __name__ == '__main__':
    main() 

Algunos de los principales problemas que tuve fueron la creación de los suscriptores y publicador, que los tenía por predeterminado en Reliable la reliability del QoS y necesitaba Best effort, debido a que los componentes de O3DE tenían esa reliability(también podría haberlo hechoo al revés).

Otro problema fue que a la hora de programar el programa, muchos errores que habían no se detectaban y tenía que estar viendo que era lo que fallaba.

Por último, tuve que añadir el segmento final del código ya que si no lo hacía, no funcionaba nada del programa, ni siquiera el primer print antes de iniciar rclpy.

Una vez conseguido realizar el programa, solo había que probarlo y este es el resultado:

This post is licensed under CC BY 4.0 by the author.

Trending Tags