move_base的缺陷

TEB避障的实际情况
无论传感器是雷达还是相机,都只能看到障碍物的一部分。如果障碍物比较大,而目标点在障碍物内(我们知道,机器人不知道),机器人会绕过它看到的障碍部分,前往目标点,然后它又看到障碍,于是接着绕行,这样会绕很久。目前只能设置参数planner_patience,绕的时间太长时,进行Abort

向move_base发布目标的频率太高,会出错

写一个loop程序,高频率循环发两个目标点,连C++程序都不用,写bash脚本即可

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
#!/bin/bash

# 每隔1秒就发布下一个目标点
while true; do

rostopic pub /move_base_simple/goal geometry_msgs/PoseStamped "header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: 'map'
pose:
position:
x: 20
y: 7
z: 0.0
orientation:
x: 0.0
y: 0.0
z: 1
w: 0" & sleep 1 && kill -2 $!

# -2 是用信号量表示的 $!是子进程号 相当于执行ctrl+C

rostopic pub /move_base_simple/goal geometry_msgs/PoseStamped "header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: 'map'
pose:
position:
x: 24
y: 7
z: 0.0
orientation:
x: 0.0
y: 0.0
z: 0
w: 1" & sleep 1 && kill -2 $!

sleep 1
echo " ---------- start next loop ---------- "
done

sleep 1 && kill -2 $!是关键,sleep 1秒就杀死进程。 如果没有这句,机器人执行第一次导航时,必须等待Ctrl+C才能进入下一次导航

经过测试,向move_base发布目标点的频率如果太高,会报错,最快为0.6秒一次。 但是关掉rviz后,可达到0.5秒一次,可见优化程序会有效。

init.py的2140行
rospy client.py 251行
这里就涉及ROS源码了,想彻底优化就得着手ROS源码了,但是感觉没有必要。


Livox-MID360

旋转式的雷达寿命短,难过车规。 Livox雷达寿命更长,符合车规

按照说明书获得雷达和电脑应设置的静态IP。说明书指出可以只连接电源线,红正黑负。直流12V

可以去Livox的官网下载LivoxViewer2_Ubuntu_v2.3.0,配置很简单。运行LivoxViewer2.sh即可

先安装Livox-SDK2,然后安装livox_ros_driver2

修改MID360_config.jsoncmd_data_ip改为电脑的静态IP,把lidar_configs里的ip改为雷达IP。 然后运行roslaunch livox_ros_driver2 rviz_MID360.launch就可以看到结果了。

参考: 配置过程


公司机器人碰撞机制的实现
Welcome to my blog, enter password to read.
Read more
如何判断机器人出了地图
Welcome to my blog, enter password to read.
Read more
如何判断到达弓字终点
Welcome to my blog, enter password to read.
Read more
如何精确追踪长直线
Welcome to my blog, enter password to read.
Read more
ROS自定义层(写法模仿静态层)加载时的阻塞问题
abstract Welcome to my blog, enter password to read.
Read more
GDB, Benchmark, perf, core dump

GDB

  • bt: 当前运行的堆栈列表
  • print: 输出或者修改指定变量或者表达式的值
  • info thread: 显示所有线程信息
  • info program: 来查看程序的是否在运行,进程号,被暂停的原因
  • run(简写r): 运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令。
  • continue(简写c): 继续执行,到下一个断点处(或运行结束)
  • next(简写n): 单步跟踪程序,当遇到函数调用时,直接调用,不进入此函数体;
  • step(简写s): 单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
  • until: 运行程序直到退出循环体; / until+行号: 运行至某行
  • finish: 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息
  • list 函数名: 将显示“函数名”所在函数的源代码,如: list main

Benchmark

Benchmark是Goole的一个开源基准测试框架,主要用于比较不同代码实现的性能和效率。Benchmak提供了丰富的测试功能,包括时、统计和分析等,可以帮助开发人员优化程序的性能和效率。

  • 安装Benchmark

可以使用包管理器或者源代码安装Benchmark。安装sudo apt-get install libbenchmark-dev1

  • 编写测试用例

首先,我们需要编写一个简单的测试函数,用于对比不同实现的性能。以计算数组元素之和为例,我们可以编写以下函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <numeric>
#include <vector>
#include <benchmark/benchmark.h>

static void BM_accumulate(benchmark::State& state)
{
std::vector<int> vec(state.range(0));
std::iota(vec.begin(), vec.end(), 0);

for (auto _ : state) {
int sum = std::accumulate(vec.begin(), vec.end(), 0);
benchmark::DoNotOptimize(sum);
}
}

BENCHMARK(BM_accumulate)->Arg(100)->Arg(1000)->Arg(10000);

这个函数使用了Benchmark提供的 tate 对象,该对象可以帮助我们迭代多次测试,并记录每次测试的结果。在函数中,我们先使用std::vector 生成一个指定大小的数组,并用 std::iota 填数组元素。然后,我们使用 std::accumulate 计算数组元素之和,并调用benchmark::DoNotoptimize 来确保这个计算不会被优化掉,最后,我们使用 BENCHMARK 宏将这个函数注册为基准测试用例,并使用Arg 方法指定测试用例的参数。

  • 运行测试

编写测试用例后,我们可以使用 benchmark::RunSpecifiedBenchmarks 函数来运行所有注册的基准测试用例,并生成测试报告。代码如下:

1
2
3
4
5
int main(int argc, char** argv)
{
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}

运行后
1
2
3
4
5
6
7
8
9
10
11
12
13
Run on (8 X 2200 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 256 KiB (x8)
L3 Unified 8192 KiB (x1)
Load Average: 1.20, 1.33, 1.18
-------------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------------
BM_accumulate/100 208 ns 208 ns 3251616
BM_accumulate/1000 2236 ns 2236 ns 313125
BM_accumulate/10000 22563 ns 22561 ns 31189

这个报告显示了每个测试用例的执行时间、吞吐量和标准差,以及与其他测试的比较。同时,也会显示出每个测试函数的代码行数和CPU 循环数等重详细的信息。除了默认的报告格式外,Goodle Benchmak 还提供了其他输出格式,例如 JSON、CSV 和 console等可以使用相应的命令行选项进行设置。
Goocle Benchmak 是一个基于 C++ 的高性能基准测试库,可以对代码的运行时间、内存使用和 CPU 循环等方面进行准确的测量和分析,帮助开发者优化代码性能。使用 Google Benchmark,可以轻松编写测试用例,自定义测试参数和运行选项,并生成详细的测试报告,方便分析和比较测试结果。

perf

在Nano上安装perf,参考这里,我下载的页面是

先用ps aux找到进程的PID,再观察进程内各个函数的CPU使用情况:sudo perf top -p <pid>
分析cartographer_node 进程

记录采样结果,以供后续分析,加上-g会记录调用链:sudo perf record -g -p <pid>

在当前终端读取采样结果:sudo perf report,会自动读取perf.data

core dump

如果进程在运行期间发生奔溃,操作系统会为进程生成一个快照文件,这个文件就叫做 core dump。之后我们可以对 core dump 文件进行分析,弄清楚进程为什么会奔溃。默认情况下,Linux 不允许生成 core dump 文件。

  1. 如果执行ulimit -c的结果是0,说明还未开启。命令ulimit -c unlimited只能在当前终端生效,所以加入~/.bashrc
  1. 指定core dump文件的路径: 修改/etc/sysctl.conf,在最后添加 kernel.core_pattern=/home/user/coredump_%e_%p_%s_%t,命名格式为 命令名_PID_导致core的信号_UNIX时间cat /proc/sys/kernel/core_pattern可以查看设置的格式。

  2. 执行sysctl -p

  3. 遇到程序非正常阻塞不运行时,在另一个终端查看其PID,然后使用 kill -s SIGSEGV <pid>产生 core dump 文件,这样就可以快速重启程序,然后慢慢分析 core dump 文件。

成功生成core dump文件时,会提示`core dumped`
  1. 执行gdb ./exec /path/coredump_file,就可以回放core dump

对接受的全局路径插值,导致move_base退出
abstract Welcome to my blog, enter password to read.
Read more
catkin_make 遇到的问题

编译之后,运行时出现这样的结果

重新编译后依然如此,只好删掉build文件夹里对应的文件,再编译后就没问题了

内存不足

catkin_make之所以有时报错内存不足,有时正常,是因为编译是按拓扑顺序,可能同时编译了move_base和teb_local_planner这两个耗内存大的包,导致报错

.so file truncated

  1. catkin_make中途 ctrl+C 造成
  2. 运行程序时,直接从VMWare关闭虚拟机

新package放入工作空间无法识别

一个新的package放入工作空间后,是不能直接识别的,无论source setup.bash还是catkin_make --pkg都不行,必须先对整个工作空间catkin_make,此时才会识别它

不同工作空间的同名package

要尽量避免这种情况,否则会混乱。此时如果有问题,用echo $ROS_PACKAGE_PATH查看环境变量包含的ROS工作空间

Could not find GTest

执行catkin_make时,有时会报错Could not find GTest,这是由于缺少测试模块,加-DBUILD_TESTING=OFF可以避免测试。

不要移植工作空间,只移植src

把ROS的工作空间转移到另一台电脑上会编译失败,build和devel里有很多文件会构成影响,即使二者的用户名一样也不行。所以每次只能复制src文件夹,放到另一台电脑的工作空间里。

我的一个自定义msg,将整个工作空间移植到另一台电脑,编译没出错,但是echo出错,好像rostopic不被识别一样:
rostopic echo 出错.png

find_package(catkin) 无法识别catkin

使用qt-ros-plugin,不知怎么操作,导致find_package(catkin)无法识别catkin,不能在任何工作空间编译,其他命令都正常。利用whereis catkin找到路径,删除相应文件,然后重装ROS

命令catkin_init_workspace:Initializes a catkin workspace by creating a top-level CMakeLists.txt.
这个命令最好不要用,创建工作空间还是新建文件夹,然后进入执行catkin_make

程序 catkin_make 尚未安装

执行catkin_make时,报错:,执行roscd等命令也提示没有安装,感觉就像是没有装ros一样。解决方法: source /opt/ros/kinetic/setup.bash

编译某个包时缺少头文件

编译禾赛雷达的驱动HesaiLidar_General_ROS,结果报错PandarScan.h: No such file or directory. 然后又catkin_make一次,竟然成功了。这时去devel/include里可以看到缺少的头文件了。 应当是第一次编译时确实缺少,然后接着编译剩下部分,此时就生成头文件了。 再编译第二次,原来需要头文件的地方就编译成功了。
参考: HesaiLidar_General_ROS/issues/24

clock skew detected

clock skew detected.png

出现这个警告是由于时钟不同步导致的,即系统时间比文件修改时间早,换到另一个Linux系统切换可能会出现这个问题。

如果在不同计算机之间传输文件,可能出现这种报警,是由于二者的UTC对时不同。现象是文件的修改时间比当前的系统时间还要晚。可能会导致某些不该编译的文件编译,或者该编译的没有编译。

在受影响的文件夹内执行一次 touch *即可永久修正这一问题。

依次执行下列指令即可

1
2
3
find . -type f | xargs -n 5 touch
catkin_make clean
catkin_make

将所有文件都重新touch一遍,更新到本地系统的时间,再make就没问题了。

The dependency target “nav_msgs_gencpp” of target does not exist

1
2
3
4
5
6
7
8
CMake Warning (dev) at planners/pure_pursuit_local_planner/CMakeLists.txt:57 (add_dependencies):
Policy CMP0046 is not set: Error on non-existent dependency in
add_dependencies. Run "cmake --help-policy CMP0046" for policy details.
Use the cmake_policy command to set the policy and suppress this warning.

The dependency target "nav_msgs_gencpp" of target
"pure_pursuit_local_planner" does not exist.
This warning is for project developers. Use -Wno-dev to suppress it.

可能加一句

1
2
3
add_dependencies(${PROJECT_NAME}
${PROJECT_NAME}_gencfg
${PROJECT_NAME}_generate_messages_cpp)