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

没什么用的目录

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<geometry_msgs::PoseStamped> (
    "/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<nav_msgs::OccupancyGrid>("/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<geometry_msgs::PoseStamped> (
    "/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可以成功

#!/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!");