В предыдущей статье мы изучили различные свойства данных радара путем экспериментов, но как данные радара отражаются в коде?
В этой статье вы узнаете, как просматривать данные радара и как обрабатывать данные радара, создавая новый пакет ros.
Во-первых, позвольте мне объяснить среду кода, которую я использую:
Версия Ubuntu: 16.04.01
ROS: кинетическая версия
Язык программирования: С++
Рекомендация IDE: в настоящее время я использую код VS, как его настроить, будет объяснено в следующей статье.
1 Формат сообщения лидарных данных в ros
Формат сообщения данных лидара в ros можно распечатать, введя следующую команду в терминале
rosmsg show sensor_msgs/LaserScan
Результат показан ниже
std_msgs/Header header // 数据的消息头
uint32 seq // 数据的序号
time stamp // 数据的时间戳
string frame_id // 数据的坐标系
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 // 雷达数据每个点对应的强度值
2 Создайте новый пакет ros
Зная структуру данных радара, мы будем использовать код для более глубокого понимания данных радара.
Сначала создайте новую рабочую область и новый пакет со следующими командами.
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src/
catkin_create_pkg lesson1 roscpp sensor_msgs
Поскольку для записи мы используем C++, первая зависимость — roscpp, а поскольку тип данных радара — sensor_msgs/LaserScan, вторая зависимость — sensor_msgs.
2.1 lesson1/src/laser_scan_node.cc
Сначала создайте новый файл в папке урока 1/src и назовите его laser_scan_node.cc. Скопируйте в него следующий код, смысл кода подробно объяснен в комментариях.
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
// 声明一个类
class LaserScan
{
private:
ros::NodeHandle node_handle_; // ros中的句柄
ros::NodeHandle private_node_; // ros中的私有句柄
ros::Subscriber laser_scan_subscriber_; // 声明一个Subscriber
public:
LaserScan();
~LaserScan();
void ScanCallback(const sensor_msgs::LaserScan::ConstPtr &scan_msg);
};
// 构造函数
LaserScan::LaserScan() : private_node_("~")
{
ROS_INFO_STREAM("LaserScan initial.");
// 将雷达的回调函数与订阅的topic进行绑定
laser_scan_subscriber_ = node_handle_.subscribe("laser_scan", 1, &LaserScan::ScanCallback, this);
}
LaserScan::~LaserScan()
{
}
// 回调函数
void LaserScan::ScanCallback(const sensor_msgs::LaserScan::ConstPtr &scan_msg)
{
ROS_INFO_STREAM(
"seqence: " << scan_msg->header.seq <<
", time stamp: " << scan_msg->header.stamp <<
", frame_id: " << scan_msg->header.frame_id <<
", angle_min: " << scan_msg->angle_min <<
", angle_max: " << scan_msg->angle_max <<
", angle_increment: " << scan_msg->angle_increment <<
", time_increment: " << scan_msg->time_increment <<
", scan_time: " << scan_msg->scan_time <<
", range_min: " << scan_msg->range_min <<
", range_max: " << scan_msg->range_max <<
", range size: " << scan_msg->ranges.size() <<
", intensities size: " << scan_msg->intensities.size());
// 第5个点的欧式坐标为
double range = scan_msg->ranges[4];
double angle = scan_msg->angle_min + scan_msg->angle_increment * 4;
double x = range * cos(angle);
double y = range * sin(angle);
ROS_INFO_STREAM(
// 第5个数据点对应的极坐标为:
"range = " << range << ", angle = " << angle <<
// 第5个数据点对应的欧式坐标为:
", x = " << x << ", y = " << y
);
// 通过ranges中数据的个数进行雷达数据的遍历
// for (int i = 0; i < scan_msg->ranges.size(); i++)
// {
// }
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "lesson1_laser_scan_node"); // 节点的名字
LaserScan laser_scan;
ros::spin(); // 程序执行到此处时开始进行等待,每次订阅的消息到来都会执行一次ScanCallback()
return 0;
}
2.2 CMakeLists.txt
Поскольку мы добавили файл .cc, нам нужно добавить параметры компиляции в этот файл в CMakeLists.txt и добавить следующее в конец файла:
# 为指定的文件生成可执行文件
add_executable(${PROJECT_NAME}_laser_scan_node src/laser_scan_node.cc)
# 为生成的可执行文件添加依赖
add_dependencies(${PROJECT_NAME}_laser_scan_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
# 为生成的可执行文件添加库的链接
target_link_libraries(${PROJECT_NAME}_laser_scan_node
${catkin_LIBRARIES}
)
2.3 package.xml
Поскольку мы используемcatkin_create_pkgПакет, сгенерированный командой, уже был настроен с помощью package.xml при создании пакета, поэтому нам не нужно изменять этот файл здесь, а только перечислить содержимое сгенерированного файла.
<?xml version="1.0"?>
<package format="2">
<name>lesson1</name>
<version>0.0.0</version>
<description>The lesson1 package</description>
<maintainer email="lx@todo.todo">lx</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>sensor_msgs</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<export>
</export>
</package>
2.4 Компиляция
После изменения файла CMakeLists.txt код можно скомпилировать. Конкретные инструкции следующие:
cd ~/catkin_ws
catkin_make
2.5 Бег
Если ничего другого, не должно быть никаких ошибок компиляции.
После завершения компиляции в папке ~/catkin_ws/devel/lib/lesson1 будет сгенерирован исполняемый файл с именем Lesson1_laser_scan_node.
Мы можем выполнить его с помощью следующей команды
首先,开一个终端,在终端中输入 roscore
再新建一个终端,在终端中输入
cd ~/catkin_ws/devel/lib/lesson1
./lesson1_laser_scan_node
Будет напечатан следующий журнал,
[ INFO] [1606545572.752075473]: LaserScan initial.
В это время никакое другое сообщение не распечатывается. Это связано с тем, что наш код не получил сообщение данных лидара, поэтому мы воспроизводим сумку с помощью следующей команды. После загрузки данных сумки щелкните правой кнопкой мыши, чтобы распаковать ее, и поместите его в папку ~/bagfiles.
(соответствует этомуданные сумкиможешь пойти к моемуОфициальный аккаунт: Создайте SLAM с нуляОтветить вlesson1Получить ссылку для скачивания,)
再次新开一个终端,输入如下命令
cd ~/bagfiles
rosbag play lesson1.bag
В это время в окне терминала, выполняющем ./lesson1_laser_scan_node, должно непрерывно выводиться следующее сообщение.
[ INFO] [1606545575.110606737]: seqence: 4131, time stamp: 1606455444.278184417, frame_id: front_laser_link, angle_min: -3.14159, angle_max: 3.14159, angle_increment: 0.00436332, time_increment: 7.15627e-05, scan_time: 0.102979, range_min: 0.01, range_max: 25, range size: 1440, intensities size: 1440
[ INFO] [1606545575.110772238]: range = 2.6, angle = -3.12414, x = -2.5996, y = -0.0453758
2.6 Анализ результатов
Из этой информации мы видим, что:
-
Система координат радара — front_laser_link.
-
Минимальный и максимальный углы данных радара составляют -3,14159 и 3,14159 соответственно.Видно, что это радар с горизонтальным углом обзора 360 градусов.
-
Ближайшее и дальнее расстояние данных радара составляет 0,01 м и 25 м соответственно.Видно, что слепая зона этого радара составляет 1 см.
-
Неделя сканирования радара вернет 1440 точек данных.
2.7 Описание
2.7.1
Из данных радара мы можем получить самую основную информацию о данных радара, но эта информация не обязательно верна и надежна, потому что эти данные записываются в пакете драйвера радара, а коды некоторых производителей радаров не стандартизированы. быть неверным. Например, слепая зона радара редко бывает меньше 1 см, а обычно превышает 10 см.
2.7.2 Преобразование координат
Кроме того, поле диапазонов в данных радара хранит только значения расстояний в полярной системе координат.Если мы хотим узнать евклидовы координаты каждой точки данных, нам также необходимо преобразовать полярные координаты.
Метод преобразования заключается в том, чтобы получить значение в диапазонах через индекс, а затем вычислить угол, соответствующий этому значению, через индекс
Значение расстояния i-й точки данных равно ranges[i] Угол i-й точки данных равен angle = angle_min + angle_increment * i Таким образом, координата x, соответствующая этой точке, равна ranges[i] * cos(angle) Таким образом, координата y, соответствующая этой точке, равна ranges[i] * sin(angle)
2.7.3 Обход данных радара
Обход данных двумерного лидара осуществляется только через цикл for по полям количества диапазонов, а значение расстояния получается через индекс.
2.8 файл запуска
2.8.1 файл запуска
В настоящее время, если мы хотим запустить этот узел, нам нужно открыть 3 терминала, чтобы запустить его.Есть ли более удобный способ запустить его?
Конечно, ROS использует файл запуска для реализации этой функции.
Прежде всего, сначала закройте все открытые терминалы, и команда для завершения того, что выполняется в ubuntu,Ctrl+C.
# 新建一个launch文件夹
mkdir -p ~/catkin_ws/src/lesson1/launch
Создайте новый файл с именем demo.launch во вновь созданной папке запуска и заполните следующее содержимое.
<launch>
<!-- bag的地址与名称,需要改成自己电脑的对应的地址 -->
<arg name="bag_filename" default="/home/lx/bagfiles/lesson1.bag"/>
<!-- 使用bag的时间戳 -->
<param name="use_sim_time" value="true" />
<!-- 启动节点 -->
<node name="lesson1_laser_scan_node" pkg="lesson1" type="lesson1_laser_scan_node" output="screen" />
<!-- play bagfile -->
<node name="playbag" pkg="rosbag" type="play"
args="--clock $(arg bag_filename)" />
</launch>
Далее, пока файл запуска запущен, он поможет нам запустить roscore, нужную ноду и воспроизведение мешка.
2.8.2 Настройка среды
Поскольку мы являемся новой рабочей областью, нам сначала нужно выполнить следующую команду, чтобы зарегистрировать индекс нашего нового пакета в терминале, чтобы терминал мог найти наш пакет.
rospack profile
source ~/catkin_ws/devel/setup.bash
Исходную команду необходимо выполнять повторно каждый раз, когда открывается новый терминал, и ее также можно записать в .bashrc с помощью следующей команды, чтобы каждый раз при открытии нового терминала исходную команду больше не нужно было выполнять. .
echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
Окружение готово, далее запускаем файл запуска через roslaunch
roslaunch lesson1 demo.launch
Если все пойдет хорошо, мы можем получить тот же результат, что и выше.
3 Резюме
В этой статье мы создали новый пакет в ROS с нуля на примере получения лидарных данных.
Мы объяснили, как создать новый пакет с помощью команд и как добавить зависимости при создании нового пакета.
После этого мы создали новый файл .cc.Содержимое в файле записано в стандартном формате ROS.В дальнейшем наши программы будут писаться в соответствии с этим режимом. В программе мы знаем содержание сообщения данных радара, как преобразовывать полярные координаты в евклидовы координаты и как перемещаться по данным радара.
После этого мы изменили файл CMakeLists.txt, и он успешно компилируется и запускается.
Наконец, мы рассмотрели файл запуска и то, как настроить среду для кода.
4 Next
В следующей статье мы не будем так подробно объяснять окружение, а уделим больше внимания реализации функций и реализации кода.
В следующей статье мы расскажем, как обрабатывать и фильтровать данные радара, как идентифицировать телят-людей в данных радара и отфильтровывать телят-людей.
Статья будет вОфициальный аккаунт: Создайте SLAM с нуляСинхронизированные обновления, каждый может обратить внимание, чтобы уведомить вас, как только статья будет обновлена.
В то же время я также надеюсь, что вы порекомендуете этот официальный аккаунт окружающим вас людям, которые занимаются лазерным SLAM, чтобы все вместе могли добиться прогресса.
существуетпубликаОтветить вlesson1доступно в этой статьеданные сумкиссылка для скачивания существуетпубликаОтветить вадрес с открытым исходным кодомВы можете получить адрес github кода в этой статье