问题描述
实验平台:TIAGo
编程语言:Python
TIAGo所使用的激光传感器在移动基座的底部,具体的描述信息如下
Laser range-finder
Located at the front of the base. This sensor measures distances in a horizontal plane. It is a valuable asset for navigation and mapping. Bad measurements can be caused by reflective or transparent surfaces.
为了获取激光数据,我们必须订阅/scan 消息,消息返回的类型为sensor_msgs/LaserScan ,该类型的文档可以访问http://docs.ros.org/indigo/api/sensor_msgs/html/msg/LaserScan.html查看,这里为了方便,我直接摘抄这个结构体的描述文档到了下面
std_msgs/Header header float32 angle_min float32 angle_max float32 angle_increment float32 time_increment float32 scan_time float32 range_min float32 range_max float32[] ranges float32[] intensities
其中ranges是一个浮点数组,每个数组成员代表着激光传感器返回的距离,这个距离有可能是inf,因为激光传感器可能会因为没有探测到物体而返回无限远。这个我们需要在后面留意一下。intensities也是一个浮点数组,用来保存对应ranges上的强度。
所有代码如下:
#!/usr/bin/env python import cv2 import numpy as np import time import rospy from sensor_msgs.msg import LaserScan import os def scan_callback(data): distances = data.ranges angle_min = data.angle_min angle_increment = data.angle_increment pixels_relative_center = [] for index in range(len(distances)): distance = distances[index] if distance == float('inf'): continue angle = angle_min + angle_increment * index x = np.cos(angle) * distance y = np.sin(angle) * distance pixel_x = int(round(x * 30)) pixel_y = int(round(y * 30)) pixels_relative_center.append((pixel_x, pixel_y)) pixels_relative_center = list(set(pixels_relative_center)) # create rgb image rgb_image = np.zeros((801, 801, 3), np.uint8) rgb_image.fill(255) pixels_relative_origin = [] for (pixel_x, pixel_y) in pixels_relative_center: col = 400 + pixel_x row = 400 - pixel_y pixels_relative_origin.append((row, col)) # draw the point for (row, col) in pixels_relative_origin: cv2.circle(rgb_image, (col, row), 2, (0, 0, 0), -1) # draw the point of robot cv2.circle(rgb_image, (400, 400), 4, (0, 255, 0), -1) cv2.imshow("rgb", rgb_image) cv2.waitKey(30) def shutdown(): cv2.destroyAllWindows() # noinspection PyProtectedMember os._exit(0) rospy.on_shutdown(shutdown) rospy.init_node('laser_image', anonymous=True) rospy.Subscriber("/scan", LaserScan, scan_callback, queue_size=5) while True: time.sleep(1)
可以持续移动机器人,将会发现数据图随着机器人的变化而变化。
代码讲解
使用循环,每次步进angle_increment 的角度,然后使用了三角函数公式来计算出激光数据点相对于机器人中心点(准确说应该是/base_laser_link,但是这里为了简便就说是中心点了)的坐标x和y。
x = np.cos(angle) * distance y = np.sin(angle) * distance
为了能够将x,y坐标转换为像素的个数(方便显示),我将他们整体扩大了30倍。实际情况中如果有map,应该结合map的分辨率来计算这个值
pixel_x = int(round(x * 30)) pixel_y = int(round(y * 30))
然后,我们新建了一个801×801的空白画布。这个画布大小是我自己定义的,足够容纳我实验环境下激光传感器返回的所有点。pixels_relative_center 数组保存的是相对于机器人中心点,激光数据点的像素坐标。在后面的循环中,我们将这些数据点转换为相对于画布原点的像素坐标,并将他们放在pixels_relative_origin 数组中。这里需要注意的是,opencv画布坐标轴的位置和方向是不一样的。400就是我们的画布中心点,所以转换方式如下
col = 400 + pixel_x row = 400 - pixel_y
最后,我们将这些点画出来即可
cv2.circle(rgb_image, (col, row), 2, (0, 0, 0), -1)