cartographer与ros环境开发经验技巧总结(持续更新)

简介:不对具体功能系统讲解,网上已经很多了,只记录关键点和踩坑点。

没什么用的目录

  • cartographer与ros环境开发经验技巧总结
  • ROS
    • 一个非官方的ROS教程
    • tf
    • ROS 中断循环的方法
    • ROS::BAG
      • 分批录制和连续播放
    • catkin rebuild
    • roslaunch log 打印
    • ros workspace
    • msg
    • subscribe回调传参
    • ROS::Time
      • clock和spinonce的关系
      • spin
      • rate+spinonce录数据出现bug
      • rate是什么?
      • 播包结束导致clock缺失
    • ros只发布一次消息会收不到的问题
    • callback绑定参数
    • rosrun
  • Cartographer
    • 环境安装
      • abseil和ceres\protobuf安装
    • 打印
    • GetYaw的实现参考
    • carto github上的issues
    • pbstream文件格式说明
  • rviz相关
    • rviz
    • 16384是rviz单个marker的上限,超过了要用markerarray
    • rviz错误码
    • geometry_msgs::PoseStamped存储与播放
  • C++库
    • gflags与catkin
    • eigen
    • gflags
    • glog
    • boost文件操作
  • 评测
    • EVO
  • 系统命令
    • kill -9 pid
    • expect
  • 系统工具
    • git
    • old mode 100644 new mode 100755
      • git rebase
    • 高斯键盘自带快捷键覆盖F10导致VSCODE无法用快捷键调试
    • 内存跟踪
    • apt-get
    • 7z
    • 抓信息
    • “beyond compare”
    • IDE vscode
      • 跳转失败的问题
    • 文本编辑
    • 资源浏览器
      • dolphin
    • terminator
  • ================================

cartographer与ros环境开发经验技巧总结

不对具体功能系统讲解,网上已经很多了,只记录关键点

ROS

一个非官方的ROS教程

https://robot-ros.com/robot

感觉很有用,至少这个tf很有用,讲的很清楚,比好多收费卖课的大忽悠要强(cvlife)
https://robot-ros.com/robot/33772.html

tf

tf主页

tf教程主页

ROS 中断循环的方法

void SigintHandler(int sig)
{
std::cout << “ros is is shutting down.” << std::endl;
ros::shutdown();
}
signal(SIGINT, SigintHandler);
while(ros::ok()){
//do
}
这样能用ctrl+c中断循环,ros::shutdown()和ros::ok()联动

ROS::BAG

官方IO demo

分批录制和连续播放

rosbag record -o $save_dir/navi_loc \
    /map \
    /scan1 \
    /scan2 \
    /odom \
    /tf \
    /odom_wheel \
    /IMU_data \
    /landmark \
    /relative_detection/relativepose \
    /localization_manager/status \
    /cart_comm_node/twist_cmd \
   --lz4  --split --duration=30m
   30分一个包,不停录制
   
rosbag play navi_loc_2022-03-17-10-33-05_0.bag navi_loc_2022-03-17-10-33-15_1.bag navi_loc_2022-03-17-10-33-25_2.bag navi_loc_2022-03-17-10-33-35_3.bag 

catkin rebuild

catkin_make --pkg --force-cmake

roslaunch log 打印


log 或 screen

If ‘screen’, stdout/stderr from the node will be sent to the screen. If ‘log’, the stdout/stderr output will be sent to a log file in $ROS_HOME/log, and stderr will continue to be sent to screen. The default is ‘log’.
cwd=“ROS_HOME|node”(optional)

ros workspace

经验证的创建ws和编译的博客

msg

(可能是特例)
工作自定义msg会安装到/opt/raccoon下,因为版本变动,需要修改一个msg(如果msg不同,C++读取msg会成为NULL,只要差一个字段就不行)。结果手动改了半天/opt/raccoon/share下的*.msg没有任何效果,dpkg”重装“msg就有效果。发现正经生效的msg应该是/opt/raccoon/include下的**.h,改完编译即可生效?还没。。。最好重新”安装“一次。
重装msg就成功了(具体的*.deb脚本那里还没研究太多)
为什么呢?因为消息*.h头文件里还有md5校验值,纯手动改字段是不行的。
而为什么python又无所谓,字段变不变都能读取消息呢?可能没有校验过程,不如C++ 严格,也取决于官方接口的实现。

subscribe回调传参

绑定回调带参数(留_1,后边是参数)

  ros::Subscriber sub2=ros_node_handler.subscribe (
    "/cartographer_ros/initialpose",100000, boost::bind(&LocPoseCallback, _1, &curr_bag_name,&bag,&new_arrival_time));

绑定类成员(参数可走类成员)

    ros::Subscriber initialpose_sub = ros_node_handler.subscribe("/cartographer_ros/initialpose", 10000000, &LocalizationEvo::InitialPoseCallback, this);
    void LocalizationEvo::InitialPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg)  
{  
  ros::Time t = ros::Time(msg->header.stamp.sec,msg->header.stamp.nsec);
  bag_->write("localization_pose_saved", t,msg);
}  

ROS::Time

根据rviz,ROS Elapsed比WalLElapsed要少,simulation的time比真实时间要慢

clock和spinonce的关系

rosbag play --clock的解释

spinonce和具体的参数设置有关,使用虚拟时间则必须按clock走,设置为false则能自然触发不阻塞。
rosparam set use_sim_time false
如果设置true,ros::time有独立的时间,设置false,ros::time::now()则是系统时间?和WallTime一样。
rviz同样也会受此参数干扰,但是需要启动之前设置(可能),并且有可能有一些“bug”,经常需要重启一下roscore才能看到一些变化,这也是比较容易产生困惑的点,很多实验不生效,则需要多重启roscore。

spin

rate+spinonce录数据出现bug

同样的计算过程,产出的pose被记录下来得到不同的长度,单独用rosbag record去记录,发现实际“丢”很多,用rostopic hz去看,50hz,但是不行rate随便设了30,加上缓冲区长度只有1,所以丢了。
106719/177200=0.6
30hz/50hz=0.6

rate是什么?

一个灵活的睡眠方案:设定10hz,100ms的间隔,但是不是睡眠100ms,你计算20ms,它睡眠80ms,你计算50ms,它睡眠50ms,是一种目标导向的接口,目标是处理频率。
问题:rate的sleep很依赖clock,如果use_sim_time,播放包的时候也是靠clock这个topic去给系统同步时间的,1.时间是否有延迟?(不影响频率,但是时间戳会有不一致,验证,打印某一pose时间和time)2.是否能保证足够精细?(通过经验看,carto用,可能范围足够,只是探究原理)

播包结束导致clock缺失

很多莫名其妙的停止与暂停都可能是缺乏clock造成的,尤其使用虚拟时间为true,并且播包结束。
keep-alive命令,播放所有内容后不结束,继续发布/clock并且时间累加。

rosbag play -k  --clock test.bag
rostopic echo /clock

接收测试,验证clock存活并累加。

ros只发布一次消息会收不到的问题

排除了名称不对,手动pub等,确定是消息发布不出去~!
但是在一个典型的while循环重复发消息的demo中就可以(但我的需求是一次)。同样的ros::ok()判断,while循环和if一次性就是不一样,后者会发不出任何消息(不是程序关闭,哪怕发布消息之后再sleep暂停也不行),必须在发布前sleep(至少3秒),消息可发出

  ros::Publisher pub = nh.advertise("/gridMap", 1);
  if(ros::ok()){//单次发送
    sleep(3.5);//起作用,加入此句后可以发出消息
    pub.publish(map);
    sleep(3.5);//不起作用
  }

原因:ROS MASTER负责协调各node,node之间需要建立点对点连接,事实上时间时给advertise<>()的,是它需要一个时延才能真正生效。

callback绑定参数

参数限制的问题直接导致无法将回调写成类成员。无法与外部交互。
低级方法:全局变量,复制消息。
正确方法:
一个用[boost绑定]

ros::Subscriber sub2=ros_node_handler.subscribe (
    "/cartographer_ros/initialpose",1, boost::bind(&LocPoseCallback, _1, &curr_bag_name,&bag,&new_arrival_time));
    
void LocPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg, std::string* curr_bag_name,rosbag::Bag* bag,ros::WallTime* new_arrival_time)  {}

一个是直接往参数列表加,但是有规则。

rosrun

没事不要乱用rosrun?

实际工程,复杂的多版本管理环境,git或许能应付,但是ros不能。
在a分支注册了一份package_mine,在b分支也注册一份,哪怕#source devel是b分支,但是rosrun仍然可能跑的是a分支。
用roslaunch。

但是可能同样不能避免,source错devel的悲剧。尤其脚本复杂,变量增加,批量操作以后。
所以存疑!!!!

Cartographer

环境安装

裸ros不够,需要安装一些库
官网安装
PS:我的工作环境还有几个包,解压3rd_deps.tar.gz安装

abseil和ceres\protobuf安装

cd  ceres-solver
mkdir build
cd build
cmake .. -DCXX11=ON
make
sudo make install
cd protobuf
mkdir build
cd build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -Dprotobuf_BUILD_TESTS=OFF ../cmake
../cmake
make
sudo make install

abseil

cd abseil-cpp
mkdir build
cd build
cmake \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
  -DCMAKE_INSTALL_PREFIX=/usr/local/stow/absl \
  ..
  make
sudo make install

官网的一些依赖包,包含lua5.2等,可参考,但是我的工作环境不需要完全照抄。
需要 liblua5.2-dev

打印

一些传感器数据相关的,打印太多会导致程序跑不动,使用LOG_EVERY_N会好一些,但是有个问题,如果是跟踪数据流,可能打印出来的时间不太一致,需要注意.

GetYaw的实现参考

cartographer中
T GetYaw(const Eigen::Quaternion& rotation)
rotation乘以单位矩阵?
arctan(y,x)

carto github上的issues

issues

pbstream文件格式说明

https://github.com/cartographer-project/cartographer_ros/issues/460

rviz相关

rviz

ros rviz中各种数据类型介绍
line_strip与line_list的区别:
0-1,1-2,2-3…
0-1,2-3,4-5…

16384是rviz单个marker的上限,超过了要用markerarray

已经修复了,但是你没更新到那个版本还是要注意
https://github.com/ros-visualization/rviz/pull/1662

rviz错误码

-11 is SIGSEGV, and -6 is SIGABRT.

/usr/include/bits/signum.h路径下找不到这个头文件,
或者使用
find /usr -name signum.h
ubuntu16.04是在
/usr/include/x86_64-linux-gnu/bits/signum.h
不同系统不同路径,用IDE引用一下头文件#include 可以跳转看到

    #define	SIGABRT		6	/* Abort (ANSI).  */
    #define	SIGIOT		6	/* IOT trap (4.2 BSD).  */

geometry_msgs::PoseStamped存储与播放

可以把非格式化的log信息转存成为bag,然后按时序播放,在rviz显示
header.frame_id=“map”
没有frame_id不能显示在rviz

C++库

gflags与catkin

只需要在cmakelist的目标中追加一个gfags即可
target_link_libraries(pose_listener ${catkin_LIBRARIES} gflags)

eigen

解决CMAKE找不到的问题&VSCODE无法调试的问题:
前提:已安装
sudo ln -s /usr/include/eigen3/Eigen /usr/include/Eigen

gflags

关于使用过程中偶然发现的一个“bug”。
DEFINE_bool(var1,false,“this is a boolean”) ;
#a.exe --var1 false
#a.exe --var1 0
无论怎么设置,FLAGS_var1都是1
后来发现是传参方法“不得当”。
我意为是–var1 空格 false
其实应该是
#a.exe --var1=false
甚至是
#a.exe --novar1
(只限于bool)
但是坑就坑在,大多数情况下,你用空格传参也都没问题,所以问题发的就比较隐蔽。
BTW:
DECLARE_bool(var1); 用于在其他文件共享使用变量
下面方法可以顺便看输入参数是什么(bool不能传更广泛的值是个遗憾,但是至少确定是ParseCommandLineFlags(从设置的默认false)修改bool值为1的)

static bool ValidateBool(const char* flagname, bool value) {
   if (value ==0)   // value is ok
     return true;
   printf("Invalid value for --%s: %d\n", flagname, (int)value);
   return false;
}
DEFINE_bool(b1, false, "bool test");
DEFINE_validator(b1, &ValidateBool);

官网说明

glog

    google::InitGoogleLogging(argv[0]);//配合gflag的?

    FLAGS_log_dir="./log/";//不会自动mkdir
	FLAGS_alsologtostderr = 1;              // 日志同时输出到stderr

    LOG(INFO) << "Hello,GLOG!  to file!";
    LOG(WARNING) << "hhhh,GLOG!  to file!";
    LOG(ERROR) << "Hello,GLOG!  to file!";
    //LOG(FATAL) << "Hello,GLOG!  to file!";
    google::ShutdownGoogleLogging();//终止

Could not create logging file: No such file or directory
你需要提前mkdir,指定的是路径不是文件名,会产出一堆文件。
$ ls log/glog_demo.
glog_demo.ERROR glog_demo.ld-TM1701.ld.log.INFO.20220325-170134.11047
glog_demo.INFO glog_demo.ld-TM1701.ld.log.WARNING.20220325-170134.11047
glog_demo.ld-TM1701.ld.log.ERROR.20220325-170134.11047 glog_demo.WARNING

boost文件操作

一些demo和简介

评测

EVO

官网
python2安装,到今天已经不太好用了,也有一些使用说明
python3版安装,有一些环境修改,如果出了问题,照着改回去

网络问题

改了python版本后会有后遗症,比如cmake报错
No module named ‘lsb_release’
后遗症解决
但是具体复制路径可能有区别,比如我是
sudo cp /usr/lib/python3/dist-packages/lsb_release.py /usr/local/lib/python3.7/
python3.7前边有个lib(我是手动装的python)

系统命令

kill -9 pid

有时候会有kill失败,用-9可以成功

expect

sudo apt-get install expect
功能是能自动完成ssh登录,批量写脚本操作

#!/bin/bash
#blabla, 创建要拷贝的路径和目标路径
    expect -c "
    set timeout -1
    spawn scp ${forwardx_user}@${forwardx_host}:${bag_files} $bag_target_path
    expect {
        yes/no {send \"yes\r\" ;exp_continue};
        password: {send \"${forwardx_pwd}\r\" };
    }
    expect eof
    "

批量拷贝文件时候有一个问题,拷贝几个文件就会断开,而且数量不固定,原因是默认timeout 30,改成-1(无限)就好了。
写法仅供参考,正常是可以#!/usr/bin/expect -f的,但是如果要写其他逻辑,可能就用bash了,然后把expect的部分用如下代码括起来
expect -c "
do something
expect eof
"

系统工具

git

本地合并冲突
跟踪远程分支的作用
应该是pull能自动获得同步,比如你是dev_hqw,你总要往develop上merge,你可以
git branch --set-upstream-to origin/develop

比如我当前是loc_evo,我想跟踪develop
建立分支跟踪的方法:
git branch --set-upstream-to=origin/develop
但是我发现一个弊端,因为我要申请merge,所以我不能和develop很好的联动,老提示我领先develop,让我上传(但是不能,我要申请merge),所以我要解锁
解锁不知道,可以重新指向,比如自己
git branch --set-upstream-to=origin/loc_evo

old mode 100644 new mode 100755

git status会显示一大堆文件变红,git diff会看到old mode new mode 错误。
这个664和755眼熟吧?当你从一个电脑把代码库复制到硬盘,复制到其他电脑,就会出这个错,一种方法可能是批量改文件权限,我觉得duck不必。
在代码库目录下,键入

git config --add core.filemode false

即可解决。。

git rebase

git rebase -i HEAD~3
合并最后三个提交记录
git rebase -i hash_a hash_c
合并hash_a到hash_c的提交
假如有abcd四个提交,合并bcd为b,直接会更新到当前分支
假如有abcd四个提交,合并bc为b,则当前处于HEAD detached 游离状态,并且此状态下不存在d的提交.
现有两个选择,git checkout main_branch,丢弃rebase操作

(上接rebase游离态)
git checkout -b temp_branch
git checkout main_branch
git merge temp_branch

自己处理一下冲突,现在的提交记录是:
a new_b d
无c的记录,有c的内容,不丢d的记录

高斯键盘自带快捷键覆盖F10导致VSCODE无法用快捷键调试

暂时无解,小米笔记本的F10通过fn+esc已经解放,笔记本键盘可以正常使用,但是高斯键盘无解。

内存跟踪

top跟踪只跟踪一个节点
pidof cartographer_node
xxxx
top -p xxxx

apt-get

update是更新源,upgrade是更新已安装软件,不要乱用。

sudo apt-get install Kolourpaint4
大小写敏感,不能用小写k,不会给你智能提示

apt-get install 自动补全
sudo apt-get install bash-completion
编辑bashrc

if [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi

7z

sudo apt install p7zip-full
-o是output,但是不加空格直接连路径
$7z x 通辽蒙牛.7z -r -o/home/ld/data/evaluating_bags/mengniu_nomap/test

抓信息

rosbag info ruiming/navi_loc_2022-01-23-11-17-27.bag | grep localization_manager/status
rostopic list | grep tf

“beyond compare”

替代品,meld,或者diff,系统自带或者apt-get即可
meld不光可以对比,可以直接点箭头编辑,像代码合并一样方便

IDE vscode

可以绑定github帐号(需要下载最新版本vscode),这样就不用每次重新下载一堆东西

vscode.cdn.azure.cn
浏览器下载deb时,替换下载链接(但是感觉很个性化,需要对应具体软件,不一定有)

vscode
方法一:
在 json 文件中添加:

方法二:
在设置中搜索format on type,勾选✔该项即可

跳转失败的问题

如果你有多级目录,每级目录都有.vscodec_cpp_properties.json

文本编辑

为了统计文本数据,替代notepad++,有一些比如kate,搜索时能显示出结果条数。

资源浏览器

官方的浏览器多标签看的眼瞎,只能看到当前目录名,根本分不清开的是什么
可选浏览器

dolphin

还不错,标签页+链接+终端+收藏,但是默认打不开terminal,需要konsole
$ sudo apt-get install dolphin konsole

terminator

右键首选项preference,layout可以保存,自带启动指令没有测试成功,窗口测试成功,配置文件在

gedit ~/.config/terminator/config

窗口名默认难以保存,可以手动加

title = window_name

路径是

directory = /home/user1/data

### terminator

================================

=====================================

展开查看

System.out.println("Hello to see U!");
System.out.println("Hello to see U!");
System.out.println("Hello to see U!");
System.out.println("Hello to see U!");

你可能感兴趣的:(SLAM,自动驾驶,人工智能,ROS,cartographer,机器人)