一直想拥有这么一个机器人,在我吃饭的时候会给我拿个板凳,在我口渴的时候能给我倒杯热水,搜来找去,便宜的是小孩子玩具,贵的几万几十万的咱也买不起,所以才想静下心来自己做一个,大概拿出10年的业余时间应该差不多吧。
疫情原因有很多时间,从零开始了探索,陆续学习了python,c ,c++,爬虫 opencv 智能识别,大概有2年多时间了,这些计算机语言对于业余选手太难了,2年多时间也只是会了复制粘贴程序,自己写还是根本完不成的。接触ros大概半年多了,踩的坑无数。
B站大学,还是从安装utuntu说起吧,安装utuntu讲的最明白的当属 六部工坊 每次安装utuntu我基本都到B站看这个up主的安装视频,人家说系统要安装50次才算熟练,我大概安装了二十多次了。在说ros系统安装,我第一次安装成功ros1用了大概10天,在看到小乌龟动起来的一刻不知道怎么形容当时的心情,中间好多次都想放弃了,因为我们用的国外的网站,经常莫名其妙的出错,中间的坎坷只有安装过得才懂。这种状况是从无意中遇到鱼总的一键安装才得以彻底解决,在此真心的感谢于总,你的一键安装太好用了,太牛了,从此安装ros再也不用提心吊胆了。系统安装好了,鱼总的视频,古月老师的视频,六部工坊的视频,还有好多机器人相关的视频,仿真过了一遍,大概半年多了接触ros,终于要开始了真实的机器人的0到1,我会把我的经历写下来与朋友们分享,并寻找有共同兴趣的朋友一起做,但是我不是计算机科班出身,每走一步会很慢很慢。
毛哥成山轮胎机油保养 发布的最佳帖子
-
不知道从何时说起--自己的一个梦
-
用笔记本自带摄像头 奥比中光深度摄像头跑通ros1单目 rgbd
环境:ubuntu20.4 ros1 noetic
奥比中光 Astra Pro RGBD深度摄像头。
联想think pad x230自带摄像头
前提:摄像头节点配置好,能够发布摄像头图像话题,orb_slam3编译成功,可以跑通自带的数据集。没有安装好请参考:
https://fishros.org.cn/forum/topic/842/视觉slam-orb_slam3在ubuntu18-04-ubuntu20-04-安装运行测试https://fishros.org.cn/forum/topic/1118/ubuntu20-4-ros1noetic-安装奥比中光-astra-pro-rgbd摄像头
orb_slam3 适配单目 双目 rgbd摄像头,最容易跑通的是单目,用笔记本自带的摄像头只需修改一下话题,就能启动。ros_mono.cc //单目主程序
/** * This file is part of ORB-SLAM3 * * Copyright (C) 2017-2021 Carlos Campos, Richard Elvira, Juan J. Gómez Rodríguez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * * ORB-SLAM3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ORB-SLAM3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with ORB-SLAM3. * If not, see <http://www.gnu.org/licenses/>. */ #include<iostream> #include<algorithm> #include<fstream> #include<chrono> #include<ros/ros.h> #include <cv_bridge/cv_bridge.h> #include<opencv2/core/core.hpp> #include"../../../include/System.h" using namespace std; class ImageGrabber { public: ImageGrabber(ORB_SLAM3::System* pSLAM):mpSLAM(pSLAM){} void GrabImage(const sensor_msgs::ImageConstPtr& msg); ORB_SLAM3::System* mpSLAM; }; int main(int argc, char **argv) { ros::init(argc, argv, "Mono"); ros::start(); if(argc != 3) { cerr << endl << "Usage: rosrun ORB_SLAM3 Mono path_to_vocabulary path_to_settings" << endl; ros::shutdown(); return 1; } // Create SLAM system. It initializes all system threads and gets ready to process frames. ORB_SLAM3::System SLAM(argv[1],argv[2],ORB_SLAM3::System::MONOCULAR,true); ImageGrabber igb(&SLAM); ros::NodeHandle nodeHandler; //ros::Subscriber sub = nodeHandler.subscribe("/camera/image_raw", 1, &ImageGrabber::GrabImage,&igb);//原 ros::Subscriber sub = nodeHandler.subscribe("/camera/color/image_raw", 1, &ImageGrabber::GrabImage,&igb); ros::spin(); // Stop all threads SLAM.Shutdown(); // Save camera trajectory SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory.txt"); ros::shutdown(); return 0; } void ImageGrabber::GrabImage(const sensor_msgs::ImageConstPtr& msg) { // Copy the ros image message to cv::Mat. cv_bridge::CvImageConstPtr cv_ptr; try { cv_ptr = cv_bridge::toCvShare(msg); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } mpSLAM->TrackMonocular(cv_ptr->image,cv_ptr->header.stamp.toSec()); }
改动的地方:
1.把主程序原来的接收topic /camera/image_raw改成 /usb_cam/image_raw"笔记本摄像头发布的话题
ros::NodeHandle nodeHandler;
//ros::Subscriber sub = nodeHandler.subscribe("/camera/image_raw", 1, &ImageGrabber::GrabImage,&igb);//原
ros::Subscriber sub = nodeHandler.subscribe("/usb_cam/image_raw", 1, &ImageGrabber::GrabImage,&igb);
ros::spin();
2安装启动摄像头
sudo apt-get install ros-noetic-usb-cam //安装摄像头驱动
roscore //启动ros核心
rosrun usb_cam usb_cam_node //启动摄像头节点
3启动单目节点
摄像头配置文件先用程序自带的,目的是先跑起来,过后在标定摄像头。
cd ORB_SLAM3
rosrun ORB_SLAM3 Mono ./Vocabulary/ORBvoc.txt ./Examples/Monocular/EuRoC.yaml
如果一切顺利,就应该能启动了,只是我的笔记本有点太老了,有点卡,但是能看到程序能正常运行了。
rgbd主程序:
ros_rgbd.cc/** * This file is part of ORB-SLAM3 * * Copyright (C) 2017-2021 Carlos Campos, Richard Elvira, Juan J. Gómez Rodríguez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * * ORB-SLAM3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ORB-SLAM3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with ORB-SLAM3. * If not, see <http://www.gnu.org/licenses/>. */ #include<iostream> #include<algorithm> #include<fstream> #include<chrono> #include<ros/ros.h> #include <cv_bridge/cv_bridge.h> #include <message_filters/subscriber.h> #include <message_filters/time_synchronizer.h> #include <message_filters/sync_policies/approximate_time.h> #include<opencv2/core/core.hpp> #include"../../../include/System.h" using namespace std; class ImageGrabber { public: ImageGrabber(ORB_SLAM3::System* pSLAM):mpSLAM(pSLAM){} void GrabRGBD(const sensor_msgs::ImageConstPtr& msgRGB,const sensor_msgs::ImageConstPtr& msgD); ORB_SLAM3::System* mpSLAM; }; int main(int argc, char **argv) { ros::init(argc, argv, "RGBD"); ros::start(); if(argc != 3) { cerr << endl << "Usage: rosrun ORB_SLAM3 RGBD path_to_vocabulary path_to_settings" << endl; ros::shutdown(); return 1; } // Create SLAM system. It initializes all system threads and gets ready to process frames. ORB_SLAM3::System SLAM(argv[1],argv[2],ORB_SLAM3::System::RGBD,true); ImageGrabber igb(&SLAM); ros::NodeHandle nh; // message_filters::Subscriber<sensor_msgs::Image> rgb_sub(nh, "/camera/rgb/image_raw", 100); // message_filters::Subscriber<sensor_msgs::Image> depth_sub(nh, "camera/depth_registered/image_raw", 100); message_filters::Subscriber<sensor_msgs::Image> rgb_sub(nh, "/camera/color/image_raw", 100); message_filters::Subscriber<sensor_msgs::Image> depth_sub(nh, "/camera/depth/image_raw", 100); typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::Image, sensor_msgs::Image> sync_pol; message_filters::Synchronizer<sync_pol> sync(sync_pol(10), rgb_sub,depth_sub); sync.registerCallback(boost::bind(&ImageGrabber::GrabRGBD,&igb,_1,_2)); ros::spin(); // Stop all threads SLAM.Shutdown(); // Save camera trajectory SLAM.SaveKeyFrameTrajectoryTUM("KeyFrameTrajectory.txt"); ros::shutdown(); return 0; } void ImageGrabber::GrabRGBD(const sensor_msgs::ImageConstPtr& msgRGB,const sensor_msgs::ImageConstPtr& msgD) { // Copy the ros image message to cv::Mat. cv_bridge::CvImageConstPtr cv_ptrRGB; try { cv_ptrRGB = cv_bridge::toCvShare(msgRGB); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } cv_bridge::CvImageConstPtr cv_ptrD; try { cv_ptrD = cv_bridge::toCvShare(msgD); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } mpSLAM->TrackRGBD(cv_ptrRGB->image,cv_ptrD->image,cv_ptrRGB->header.stamp.toSec()); }
修改orb_slam3话题为自己的rgbd相机话题
message_filters::Subscriber<sensor_msgs::Image> rgb_sub(nh, "/camera/color/image_raw", 100);
message_filters::Subscriber<sensor_msgs::Image> depth_sub(nh, "/camera/depth/image_raw", 100);启动rgbd摄像头
. devel/setup.bash
roslaunch astra_camera astra_pro.launchm@r:~$ rostopic list
/camera/color/camera_info
/camera/color/image_raw
/camera/depth/camera_info
/camera/depth/image_raw
/camera/depth/points
/camera/depth_registered/points
/camera/extrinsic/depth_to_color
/camera/ir/camera_info
/camera/ir/image_raw
/camera/reset_device
/rosout
/rosout_agg
/tf
/tf_static
启动rgbd主程序 (摄像头都没有标定,用的程序自带的配置文件)
cd ORB_SLAM3
rosrun ORB_SLAM3 RGBD ./Vocabulary/ORBvoc.txt ./Examples_old/ROS/ORB_SLAM3/Asus.yaml
程序能跑起来了,要想数据准确,需要给摄像头作标定,rgbd深度摄像头计算量应该是比单目的小,运行比较流畅。
-
RE: 为什么雷达在fixed frame base_link不显示,只能在fixed frame laser下才能显示呢?
问题解决了,我的雷达的默认fixed_frame 是 laser 编写ufdf文件,我按鱼总讲课的代码
<link name="laser_link"> <visual> <origin xyz="0 0 0" rpy="0 3.14159 0"/> <geometry> <cylinder length="0.04" radius="0.04"/> </geometry> <material name="black"> <color rgba="0.0 0.0 0.0 0.8" /> </material> </visual> </link>
把名字从laser_link改成laser雷达就能显示了
<link name="laser">
-
RE: 踩坑--激光雷达安装
参考以下网址,usb端口号不固定问题完美解决。
https://blog.csdn.net/weixin_40639095/article/details/108490329 -
为了修改一段代码,我用了2个多月的时间学了一遍c++
先不分享代码,先分享这段时间学习c++的经历吧.
b站 黑马程序员 c++入门,老师讲的是相当好.但是他用的Visual Studio,是Window平台用的,对于我们ros的utuntu平台不支持,我们在utuntu平台用的最多的还是VScode,所以还是说说怎么跟着他的课程用VScode吧.
VScode是编辑器,需要自己下载编译软件才能使用.(我是业余爱好,不是专业程序员,说的不对的多包含)
1 VScode下载安装和插件安装看鱼总的视频.
2 安装gcc g++ 编译器命令 打开终端输入sudo apt install build-essential gdb
3 在当前文件夹编译命令, g++ 文件名 在当前文件夹生成 a.out 文件
4 运行生成的文件 ./a.out
对于我们学习c++ 程序这就够了,简单易用.随着我们越来越熟练 可以给编译加上参数 g++ 文件名 -o 生成的文件名.以后还有用gdb调试程序,但是一开始越简单越好.
看完了黑马程序员,我又跟着 b站 码农论坛 学了一遍,真正的实战学习,没有花活,把c 和 c++ 统一起来了,在高手眼里,c 和 c++就是一种语言.
学习心得,一定要跟着老师敲代码,只看永远看不会,因为在敲的同时,加深了大脑的记忆和理解.
通过以上的学习,在跟着鱼总的课程敲一遍,大概就能看懂c++的代码了.
没有c++的基础,机器人就别学了,和天书一样,根本看不懂的. -
轮毂电机机器人底盘foxy版代码跑通,把在foxy踩过的坑和经验分享
硬件配置:联想x230笔记本作主控,普通平衡车轮毂电机,轮毂电机控制板,雷神M10激光雷达,另一台联想t470笔记本做远程控制。
为了远程控制机器人,刚刚入手的一台联想t470,两千多一点,16g内存 i5处理器 500固态硬盘,win10系统,为了测试一下虚拟机性能,这台笔记本按鱼总的课程安装的ubuntu 20.4虚拟机,当时计划如果太卡就在安装双系统,经测试,虚拟机运行非常稳定,和真正的ubuntu机子区别不大。
不得不说,鱼总的一键装机真的是太牛了,没有刷到鱼总前我第一次装ros装了半个多月,当时差点就放弃了,现在装ros几分钟搞定。感谢鱼总!!!!!!!!
人家说熟练装机需要50遍,我没有具体算过,不过我觉得2-30十次是有了,说这些只是为一些初学者打打气。
对于ros经常出现的莫名其妙的问题,我想做过的肯定身有体会,我觉得和自动安装依赖的这2个命令有关系。rosdepc install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y
colcon build --packages-up-to cartographer_ros
因为我们是在学习,肯定会下载很多人的代码,好多代码里面有重复的包,经过自动安装依赖把有用的东西多次覆盖了,导致系统故障,到最后只能重装系统。
雷达超出了车体,容易撞坏了,向里面移了一点
笔记本做主控有一个好处就是配置比树梅派高,实验完了还能利用,但是需要单独充电,不是太方便。
我从今年六月份就买了轮毂电机和轮毂电机控制板,为什么用了这么久才跑通代码呢,我的轮毂电机控制板没有odom话题,卖家给我提供的代码不是foxy版的,c++我又看不懂,为了看懂c++的代码我又学了2个多月c++,才把odom话题拼凑出来,感谢你碰到的每一个错误吧,因为这些错误会让你学会很多东西,如果你只是买一套现成的配件大概不超过一个星期就能跑通,但所基本上什么也学不会。代码一定要自己抄 ,只是看永远学不会,鱼总的代码有的我抄了好几遍才能看懂。
轮毂电机是大功率底盘最经济的选择,里面自带计数,节省很多成本,非常皮实,我用的这个控制板不知道是虚接还是程序有bug,在外面砖铺的颠簸路面有时会轮子不受控制,在平整的室内用的还是挺好用的,下一步要研究一行stm32,弄块皮实的控制板。
urdf模型 建图 导航用的鱼总讲课的代码,代码跑通了,但是还很不稳定,下一步升级ros2 用humble在弄细节 -
学习笔记
------------------------------常用命令-------------------------
upower -i /org/freedesktop/UPower/devices/battery_BAT0 查看笔记本电量
txy:43.138.104.65
windows使用git---------------------- 1 安装
官网下载 Git 安装包 https://git-scm.com/
选择安装目录,一直点击next,点击install,最后点击finish完成。开始菜单里找到“Git”->“Git Bash”,就说明Git安装成功
文件夹内按shift鼠标右键单击--在此处打开powershell窗口 git --version查看版本号git version 2.42.0.windows.2 - 2 配置环境变量(默认安装一般不需要配置,除非加载有问题)
输入命令行 where git并回车,复制返回的地址
我的电脑右键 =》属性 =》高级系统设置 =》系统属性(高级)=》 环境变量,进入环境变量对话框
选中 系统变量 里的 Path ,点击编辑。
点击 新建 ,粘贴刚刚复制的地址去掉 git.exe
C:\Program Files\Git\cmd
终端输入git 有一大坨内容说明环境变量配置成功。 - 3 配置用户名邮箱,只需配置一次:
git config --global user.name "清风"
git config --global user.email 24879554@qq.com
查看配置是否成功:git config --global --list
Git 首次安装必须设置一下用户签名,否则无法提交代码。这里设置用户签名和将来登录 GitLab(或其他代码托管中心)的账号没有任何关系。 - 4 git常用命令
git init 初始化项目
git status 查看当前目录下文件的状态
git add (文件名 | .)添加到暂存盘,文件名代表某文件,"."代表所有文件
git commit -m "备注" 提交到git本地仓库,产生新版本,引号中的备注必须写
git log 查看所有提交的记录
git log --pretty=oneline //只查看一行日志
git clone 链接 克隆远程仓库,进行连接
git reflog 查看历史版本号
git reset --hard HEAD^ //回退上一个历史版本。
在Git中,用HEAD表示当前版本,也就是最新的提交1094adb...,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
git reset --hard 1094adb7 //用指针方式回退到指定版本 - 5 分支管理 创建dev分支,然后切换到dev分支
git checkout -b dev = git branch dev git checkout dev
git branch //查看当前分支
git checkout master //切换分支
git merge dev //合并分支
git branch -d dev //删除分支
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全 - 6 把本地项目托管到码云:
1注册并激活账号
2生成并配置公钥C:\Users\Think.ssh 记事本打开id_ed25519.pub 复制公钥内容
码云 设置 安全设置 ssh公钥 把复制的公钥添加,标题可以随便写 ssh -t git@gitee.com 验证公钥是否成功
3新建仓库 输入仓库名称 私有 创建
4选ssh方式 git remote add origin git@gitee.com:mangguo123b/uni-shop2.git 关联本地仓库和码云仓库
项目根目录终端 git push -u origin "master" 本地仓库推送到码云仓库。
git branch //查看本地分支名 git branch -r ,查看远程的分支名
git如何避免”warning: LF will be replaced by CRLF“提示?linux换行LF /n windows换行CRLF 回车/n
git config --global core.autocrlf true //windows
-------------markdown格式------------------------
在文字前加个#号和一个空格就能设置成标题,一级标题就用一个#号,二级标题就用两个#号,以此类推;
在文字两边加** 表示对包围的文字加粗
在文字两边加*表示对包围的文字做斜体
在文字前加>和一个空格表示引用这句话
在空白处输入***表示一条分割线
在文字前加-和一个空格表示无序列表
在文字前加阿拉伯数字、一个英文句号.和一个空格表示有序列表,如1. 2. 3.
用[显示文本](链接地址)表示插入超链接
用表示插入图片
--------------------------ros2------------------
ros2 launch jtbot robot.launch.py 启动机器人
ros2 launch jtbot_navigation2 navigation2.launch.py 启动导航
echo $ROS_DISTRO //显示版本环境变量
ros2 run turtlesim turtlesim_node //启动乌龟
ros2 run turtlesim turtle_teleop_key //启动键盘控制
ros2 run teleop_twist_keyboard teleop_twist_keyboard //启动键盘控制
ros2 topic pub /demo/cmd_demo geometry_msgs/msg/Twist "{linear: {x: 0.2,y: 0,z: 0},angular: {x: 0,y: 0,z: 0}}"
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args --remap cmd_vel:=cmd_vel1
sudo apt-get install python3-colcon-common-extensions //安装colcon
mkdir -p town_ws/src //创建工作空间和功能包 -p 递归创建目录
cd town_ws/src
ros2 pkg create village --build-type ament_python --dependencies rclpy //创建python功能包
ros2 pkg create village --build-type ament_cmake --dependencies rclcpp //创建c++包
colcon build --packages-select fishbot //编译某一个功能包
--symlink-install //加软链接launch文件不用编译就生效
rosdepc install -i --from-path src --rosdistro foxy -y //安装包依赖
colcon build --packages-up-to cartographer //--packages-up-to,编译其所有依赖后再编译该包
echo 'source ~/ros2_ws/install/setup.bash' >> ~/.bashrc //写入环境变量 >> 重定向文末追加
ros2 话题工具--------------------------------
ros2 topic list
ros2 topic echo /imu_data
ros2 topic info /imu_data
ros2 topic pub /chatter std_msgs/msg/String 'data: "123"' //手动发布话题
ros2 节点node----------------------------------
ros2 node list 查看节点列表
ros2 node info <节点名>查看节点详细信息
ros2 服务 service------------------------------
ros2 service list 查看服务列表
ros2 service type /set_pose 查看服务接口类型
ros2 参数 param-------------------------
ros2 param list 查看参数列表
ros2 param describe turtlesim background_b # 查看某个参数的描述信息
ros2 param get turtlesim background_b # 查询某个参数的值
ros2 param set turtlesim background_b 10 # 修改某个参数的值
ros2 param dump <node_name> //下载保存参数为yaml文件:ros2 param dump /turtlesim
ros2 param load /turtlesim ./turtlesim.yaml //恢复参数值
ros2 run <package_name> <executable_name> --ros-args --params-file <file_name> //加载参数启动节点
ros2 run turtlesim turtlesim_node --ros-args --params-file ./turtlesim.yaml --remap cmd_vel:=cmd_vel1
生命周期节点-----------------------------
ros2 lifecycle get /bt_navigator
ros2 lifecycle set /bt_navigator configure //设置声明周期节点状态,可以设置的状态有下面几个
configure,cleanup,activate,deactivate,shutdown
ros2 lifecycle list /bt_navigator //状态列表
ros2接口 interface-------------------------------
ros2 interface list 查看接口列表(当前环境下)
ros2 interface packages 查看所有接口包
ros2 interface package std_msgs 查看某一个包下的所有接口
ros2 interface show std_msgs/msg/String 查看某一个接口详细的内容
ros2 interface proto sensor_msgs/msg/Image 输出某一个接口所有属性
自定义接口使用方法:话题接口 服务接口 动作接口:
1 修改package.xml 加入代码<depend>village_interfaces</depend>
2修改CMakelists.txt 加入代码
find_package(village_interfaces REQUIRED) find_package是cmake的语法,用于查找库
找到后,还需要将其和可执行文件链接起来 所以还需要修改ament_target_dependencies
ament_target_dependencies(wang2_node rclcpp village_interfaces)
ros2 工具------------------------
rqt-->node_graph 节点关系图
ros2 run tf2_tools view_frames.py //在当前文件夹生成TF树pdf文件,在humble去掉 .py
ros2安装摄像头驱动------------------
sudo apt install ros-foxy-usb-cam//foxy安装摄像头驱动
ros2 run usb_cam usb_cam_node_exe//启动摄像头节点
ros2 launch usb_cam demo_launch.py //启动摄像头节点
//启动单目摄像头orbslam3
ros2 run orbslam3 mono ~/ros2_ws/src/ORB_SLAM3/Vocabulary/ORBvoc.txt ~/ros2_ws/src/ORB_SLAM3/Examples/Monocular/EuRoC.yaml
vi /opt/ros/foxy/share/usb_cam/config/params.yaml //修改此文件可以修改启动哪个摄像头和分辨率:
video_device: "/dev/video0"//启动内置摄像头video_device: "/dev/video2"//启动外置摄像头
image_width: 640/1280 image_height: 480/720 //修改分辨率
奥比中光摄像头ros2 foxy--------------------
source /opt/ros/foxy/setup.bash
source ./install/setup.bash
ros2 launch astra_camera astra_mini.launch.py //ros2启动奥比摄像头
ros2foxy 启动rviz2
source /opt/ros/foxy/setup.bash
source ./install/setup.bash
rviz2 -d src/ros2_astra_camera/astra_camera/rviz/pointcloud.rviz
ROS机器人里程计模型:线速度V和角速度ω 左右轮速VL和VR 轮距D=2d
正运动学:V=(VL+VR)/2 角速度ω=(VL-VR)/D轮距
运动学逆解:VL =V+ωd VR =V-ωd
--------------------模型----------------
sudo apt install ros-$ROS_DISTRO-joint-state-publisher ros-$ROS_DISTRO-robot-state-publisher //安装关节发布节点
--------------------xacro->urdf ----------------------
xacro文件不能在launch直接使用,需要转成urdf文件
用法1:当前文件夹打开终端输入:xacro model.xacro > model.urdf 生成纯urdf文件
----------------------slam建图------------------------
sudo apt install ros-foxy-cartographer
sudo apt install ros-foxy-cartographer-ros
ros2 launch jtbot_cartographer cartographer.launch.py //运行建图节点
sudo apt install ros-foxy-nav2-map-server //安装地图服务节点
cd src/jtbot_cartographer/ && mkdir map && cd map
ros2 run nav2_map_server map_saver_cli -t map -f jtbot_map //保存地图
---------------------------nav2导航------------------
sudo apt install ros-foxy-nav2-
#修改nav2_params.yaml配置文件
robot_radius: 0.35 //修改机器人半径 inflation_radius: 0.1 //修改膨胀地图半径
-------------------------ros1--------------------------卸载ros的方法------------------
sudo apt-get autoremove --purge ros-* //卸载全部ros:
sudo apt-get autoremove --purge ros-indigo //卸载某个ros版本(ros版本可以共存,每次需要切换)如indigo:ROS一键安装
wget http://fishros.com/install -O fishros && . fishros
ubuntu 18.04 Melodic ros1 旋律--------------
mkdir -p demo_01_ws/src //创建工作空间
cd demo_01_ws/src
catkin_create_pkg hello roscpp rospy std_msgs //创建功能包
catkin_make -DCATKIN_WHITELIST_PACKAGES="astra_camera"//ros1单独编译包
~/demo01_ws$ source ./devel/setup.bash //添加环境变量
echo $ROS_PACKAGE_PATH //显示空间路径
roscore //启动核心 rosrun turtlesim turtlesim_node //启动乌龟 rosrun turtlesim turtle_teleop_key //启动键盘
rosnode list rosnode info //查看节点信息 rosrun rqt_graph rqt_graph //节点图形界面
rostopic echo /turtle1/cmd_vel //显示话题数据 rostopic list //话题 rostopic type /turtle1/cmd_vel //话题类型
rosservice list //服务 rosservice type /spawn //服务类型 rosparam list //参数列表
roslaunch beginner_tutorials turtlemimic.launch //启动launch
奥比中光摄像头ros1安装--------------------
https://fishros.org.cn/forum/topic/1118/ubuntu20-4-ros1noetic-安装奥比中光-astra-pro-rgbd摄像头
source ./devel/setup.bash
roslaunch astra_camera astra_pro.launch //ros1启动相机
export ROS_PACKAGE_PATH=${ROS_PACKAGE_PATH}:/home/m/ORB_SLAM3/Examples_old/ROS //导入ros1包临时地址
cd ORB_SLAM3
rosrun ORB_SLAM3 RGBD ./Vocabulary/ORBvoc.txt ./Examples_old/ROS/ORB_SLAM3/Asus.yaml //启动ros1 rgbd slam3
ros1相机标定-------------------
rosrun camera_calibration cameracalibrator.py --size 9x6 --square 0.02 image:=/usb_cam/image_raw camera:=/usb_camcamera:=/usb_cam
ros1安装摄像头驱动-------------------
sudo apt-get install ros-noetic-usb-cam //ros1安装摄像头驱动
rosrun usb_cam usb_cam_node //启动摄像头节点
roslaunch usb_cam usb_cam-test.launch//启动摄像头launch节点
--------------windows常用命令---------------
ipconfig //查看本机ip
tracert -d 192.168.0.104 跟踪路由
nslookup bilibili.com 查看网址ip地址
---------------------utuntu 基础知识 ---------------------------
常用命令-----------------------------
sudo init 0 //关机, sudo init 6 //linux重启, pwd //查看当前路径目录, cd ..//退到上级目录, cd //退到用户目录,
. 或者 ./是当前目录 .. 或者 ../是父级目录 /是根目录
ifconfig //查看网络信息, ip addr //查看网络信息, top //查看进程 性能分析, history 查看历史命令,
ctrl+alt+t //启动终端, ctrl+c //强制退出,
sudo find / -name *.txt 全目录查找文件
Linux du命令:全称是 disk usage,查看文件夹和文件的磁盘占用情况
du -sh * 计算子文件夹大小du -sh * |sort -hr 大小排序
df df -m df -h 查看系统磁盘分区 -m以兆为单位 -h以g为单位
free -h //查看内存和交换区free -h以g为单位, du -h //统计文件大小 -h以g为单位
date //查看时间, date -s "2023-01-18 09:30:25" //修改时间
截屏快捷键 PtrSc //全屏 shift+prtsc 截取合适大小
用户管理------------------------------------
groupadd 组名 //创建组, groupdel 组名 //删除组, vi /etc/group //组信息保存文件
useradd -N 用户名 -g 组名 -d 用户目录 //创建用户, userdel 用户名 //删除用户, vi /etc/passwd //用户信息保存位置
passwd 用户名 //修改密码, su - ubuntu //切换用户
文件操作--------------------------------
常用压缩打包命令:tar -zcvf tarame.tar.gz dir/files
常用解压缩命令:tar -zxvf tarname.tar.gz -C 指定解压后文件存放地址
mkdir <文件夹名> //创建文件夹, gedit <文件名> //创建文本文件, touch <文本名> //创建新文本
vi<文件名> //创建或者编译文件, nano <文件名> //编辑文件, cat <文件名> //查看文件内容
more 文件名 查看文件内容 空格显示下一页 b显示上一页 q退出
cp -r 旧目录或文件名 新目录或文件名 -r复制目录 没有-r只能复制文件
mv 旧目录或文件名 新目录或文件名 移动目录或者文件
ls 查看所选文件夹 ls-a 查看文件夹内所有文件
ls -l显示文件信息 ls -lt按时间顺序显示文件信息
ctrl+h 显示文件夹内隐藏文件
rm -rf 删除系统文件夹前面加 sudo -r表示删除目录,没有-r只能删除文件 -f强制删除,不需要确认
r=4 w=2 x=1 rwx=7 rw-=6 -ws=3 -w-=2 --x=1 ---=0 r读w写x执行
目录和文件权限--------------------------
chown -R 用户:组 目录和文件列表 # 转移文件或目录所有权,-R 选项表示连同子目录一起修改
chmod -R 三位8进制权限 目录或文件列表 修改文件权限,-R表示连同子目录一起设置。
sudo chmod 777 demo # 修改demo文件权限 7 usr 7 group 7 other
chmod -R u=rwx demo #修改demo文件权限另一种方法,u /g /o usr group othre = + - 重新给权限赋值 -R表示连同子目录一起设置。
ls |more 管道符号 空格 下一页 q退出
ln 文件名 链接名 文件只能创建硬链接 ln 1.txt /home/1.txt 给文件起别名,可以跨目录,不可跨文件系统
ln -s 目录或文件名 链接名 ln -s /home/aa.txt /root/aa.txt 软链接类似windows的快捷方式
超级终端terminator-------------------------------
sudo apt install terminator //安装
ctrl+shift+e 横向分屏,ctrl+shift+o 纵向分屏,ctrl+shift+w 取消分屏,alt+方向键 移动焦点
分屏失败 出现横杠e 是因为激活了输入法快捷键
终端输入ibus-setup 输入法设置 表情符号 删除对应表情符号
上古神器vi---------------------------------------
vi 文件名 打开文件 按 i 输入模式 按esc 命令
命令模式按 :x 回车 保存退出 :wq 回车 保存退出
k 上 j 下 h 左 l 右 G跳到最后一行首
ctrl +insert 相当于ctrl+c 复制 shift+insert 相当于ctrl+v 粘贴
/abcd //查找abcd n //查找下一个, u //撤销 :w //存盘 :w!//强制存盘 :w文件名 //文件另存为
:q不存盘退出 :q!不存盘强制退出
ssh----------------------------------
ssh m@192.168.0.1 输入密码远程登陆 logout退出远程连接
将远程服务器上/media/data(文件夹)下的data.ini文件复制到本地/data文件夹下,命令:
scp user_remote@172.27.14.67:/media/data/data.ini /data/data.ini
将远程服务器上/media/data(文件夹)下的所有文件复制到本地/data文件夹下,命令:
scp -r user_remote@172.27.14.67:/media/data /data
sudo apt install openssh-server 安装ssh服务端
上传下载文件-------------------------------
sftp连接服务器 ls //查看服务器文件, lls //查看客户机文件, lcd lpwd
put 文件 //上传到服务器 get 文件 //下载到window客户机
exit //退出 unzip aaa.zip //解压zip文件 通用格式
软件包安装卸载------------------------------------
sudo apt-get install <文件名> //安装程序, sudo apt-get remove <文件名> //卸载程序
linux 进程------------------------
ps -ef ps -ef|grep demo 查看系统进程
kill 进程编号 终止进程 顽固进程 kill -9 进程编号 杀死进程
网络设置-----------------------------------
ip addr 查看linux网络信息, cd /etc/sysconfig/network-scripts/
vi ifcfg-ens33 vi编辑网络配置文件 在后面加上以下代码
#设置固定IP 桥接模式
ONBOOT=yes #默认启动网卡
BOOTPROTO=static #dhcp-动态ip,static-静态ip
IPADDR=192.168.0.11 #ip地址
NETMASK=255.255.255.0#子网掩码
GATEWAY=192.168.0.1 #网关
DNS1=8.8.8.8.8 #谷歌dns
DNS2=114.114.114.114 #电信dns
hostnamectl set-hostname 主机名 更改主机名
ping www.baidu.com 测试网络联通性
edge浏览器安装-------------------------
下载网址:https://www.microsoft.com/zh-cn/edge/download?form=MA13FJ
安装:sudo dpkg -i microsoft-edge-stable_117.0.2045.35-1_amd64.deb
环境变量----------------------------
env|grep PATH #查看环境变量 , echo $PATH #查看环境变量
export PATH=/usr/local/sbin:/usr/local/bin 设置环境变量 中间用:分割。
export PATH=$PATH:/bb export PATH=$PATH:. 新增环境变量的2种方法 .表示当前目录加入环境变量
LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径。
在linux终端下输入:export LD_LIBRARY_PATH=NEWDIRS:$LD_LIBRARY_PATH 设置临时环境变量 可以在 ~/.bashrc 末尾加上上面的命令每次打开 shell 都读取一次shell脚本 test.sh---------------------------------------------
#!/bin/bash //添加解释器
echo "Hello World !" //echo表示输出
//echo hello A > tmp.txt //echo hello A >> tmp.txt //将字符串输出重定向,当前目录没有tmp.txt,则创建tmp.txt,并将字符串输出到tmp.txt文件中,>>追加到文件末尾
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
----------------------c学习--------------------------
占位符-----------------------------
%c 字符 %s 字符串 %e 科学计数法输出double %p 输出内存地址
%f float 占4个字节 %lf double 占8个字节 %Lf long double 16个字节
在实际开发中,建议弃用float,只采用double就可以,long double暂时没有必要
%hd、%d、%ld 以十进制、有符号的形式输出short、int、long 类型的整数。
%hu、%u、%lu 以十进制、无符号的形式输出short、int、long 类型的整数。
3e2 310^2 3e-5 30.1^5科学计数法
数据类型(简介)
boolean 布尔型 char 字符型 unsigned char 无符号字符型 byte 字节型 int 整型 long 长整型unsigned long 无符号长整型 float 浮点型 double 双精度浮点型 string 字符串 字符串型 array 数组
-----------------------------c++学习--------------------
c++编译------------------------
sudo apt install cmake
g++ project.cpp 编译单个文件
-std=c++11 ,-std=c++14 //指定版本命令,-Wall //开启所有警告
gdb调试------------------------
sudo apt install build-essential gdb
gcc -g test.c -o test //-g带调试参数编译
gdb test //调试启动 (gdb) q 退出调试
(gdb) l // list 简写 l查看源程序代码,默认显示10行,按回车键继续看余下的。
(gdb) b 5 //break 简写 b 在某行设置断点
(gdb) r //run 简写r 运行程序直到遇到 结束或者遇到断点等待下一个命令
(gdb) n (gdb) s //next简写 n 单步执行,不进入函数 step简写 s 单步执行,遇到函数会进入函数
(gdb) c //continue简写 c 继续执行程序,直到下一个断点或者结束
cmake-----------------------------------------
#CMAKE内置变量
CMAKE_BINARY_DIR,PROJECT_BINARY_DIR,<projectname>_BINARY_DIR #顶层二进制目录
CMAKE_SOURCE_DIR,PROJECT_SOURCE_DIR,<projectname>_SOURCE_DIR #主cmakelists.txt所在路径
CMAKE_CURRENT_SOURCE_DIR //前正在处理的源目录(CMakeLists.txt所在目录)
使用message函数,分为三个消息类型:FATAL_ERROR(致命错误) WARNING(警告) STATUS(正常)
aux_source_directory(. SRC_LIST) #指定目录源文件都加入SRC_LIST变量
cmake最小系统---------------------------
cmake_minimum_required(VERSION 2.8) #版本号
project(hello) #工程名
INCLUDE_DIRECTORIES(~/cxx/include/)#添加第三方头文件搜索路径,如果头文件在usr/local/include系统目录内则可以不添加
add_library(hello SHARED hello.cpp) #生成库文件 SHARED 动态库 STATIC 静态库
add_executable(main main.cpp) #生成可执行文件main
target_link_libraries(main hello)#链接第三方库,库在系统环境变量/usr/local/lib里面可以只写库名
target_link_libraries(main /home/cxx/libhello.so)#链接第三方库,库不在/usr/local/lib里面可以写库的完整路径
add_subdirectory(src) #添加子目录src
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)生成的库文件放置路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)设置最终目标文件存放的路径。
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/Examples/)#生成的可执行文件放置路径
#cmake install 安装默认路径 CMAKE_INSTALL_PRERIX=/usr/local/
#TARGETS 生成的目标文件 #FILES 文件安装 # PROGRAMS 非目标文件可执行脚本 # DIRECTORY 目录安装
install(FILES hello.h DESTINATION include) #安装文件(头文件 普通文件)
install(TARGETS hello_static ARCHIVE DESTINATION lib) #安装静态库
install(TARGETS hello LIBRARY DESTINATION lib) #安装动态库
find_package用法----------------------------------------
库目录编写 Findhello.cmakefind_path(HELLO_INCLUDE_DIR hello.h /usr/include/ /usr/local/include/)#find_path指定了头文件的路径 find_library(HELLO_LIBRARY NAMES hello PATHS /usr/lib/ /usr/local/lib/)#指定查找库文件.so的路径 if (HELLO_INCLUDE_DIR AND HELLO_LIBRARY) set(HELLO_FOUND TRUE) endif (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
CMakeLists.txt 设置
set(CMAKE_MODULE_PATH "/usr/share/cmake/Modules/") #设置Findhello.cmake 搜索路径
find_package(hello)
include_directories(${HELLO_INCLUDE_DIR}) #包含库的头文件
add_executable(main main.cpp) #生成可执行文件main
target_link_libraries(main ${HELLO_LIBRARY}) #将源文件与库文件链接起来
-----------类和对象封装 继承 多态-----------
多态---------------------------------
静态多态:函数重载和运算符重载属于静态多态,复用函数名。
1函数重载:重载函数的关键是函数参数列表,包括:函数的参数数目和类型,以及参数的排列顺序,重载函数与返回值,参数名无关。
2动态多态:派生类和虚函数实现运行时多态。
有继承关系 子类重写父类中的虚函数 父类指针或者引用指向子类对象
重写:函数返回值类型 函数名 参数列表完全一致为重写。
---------------------opencv-------------------------
opencv4.4安装--------------------------
首先完全卸载刷机时自带的opencv旧版本,不同版本版本会引起冲突。- 先到opencv编译安装的目录build下
cd build
sudo make uninstall
cd ..
sudo rm -r build
2.也可以手动删除,总之删除干净即可。
sudo rm -r /usr/local/include/opencv2 /usr/local/include/opencv /usr/include/opencv
/usr/include/opencv2 /usr/local/share/opencv /usr/local/share/OpenCV /usr/share/opencv
/usr/share/OpenCV /usr/local/bin/opencv* /usr/local/lib/libopencv*
3.检查是否删除完
pkg-config opencv --libs
pkg-config opencv --modversion
没有删除干净在用下面的命令,干净了就不用了,下面命令劲有点大,会连同依赖给删除了。
sudo apt-get purge libopencv*
sudo apt autoremove
sudo apt-get update
安装opencv 4.4
2 安装cmake以及依赖库
sudo apt-get install cmake
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg.dev libtiff4.dev libswscale-dev libjasper-dev
3 OpenCV源码下载官网地址: https://opencv.org.
opencv_contrib下载地址: https://github.com/opencv/opencv_contrib
解压: opencv-4.4.0.zip opencv_contrib-4.4.0.zip
新建opencv文件夹,把解压的2个文件夹放入
sudo apt update && sudo apt install -y cmake g++ wget unzip
cd opencv
mkdir -p build && cd build
cmake -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.4.0/modules ../opencv-4.4.0
cmake --build .
sudo make install
4 把opencv的so库加入到环境变量
cd /etc/ld.so.conf.d
touch opencv.conf
sudo gedit opencv.conf
在空白文件opencv.conf里写入:/usr/local/opencv3.4.0/lib
sudo ldconfig
输入如下命令 sudo gedit /etc/bash.bashrc #在弹出文件的末尾加入PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH,保存退出。
#检测opencv
pkg-config --modversion opencv
pkg-config --cflags opencv
pkg-config --libs opencv
Ubuntu18.04 + ROS 终端在 /usr/local 路径下安装opencv4.1.1
https://blog.csdn.net/qq_38429958/article/details/123185284
opencv.cpp#include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { Mat srcImage = imread("lena.jpg"); imshow("源图像",srcImage); waitKey(0); return 0; }
CMakeLists.txt
cmake_minimum_required(VERSION 2.8) project(OPENCV) find_package(OpenCV REQUIRED) add_executable(opencv opencv.cpp) target_link_libraries(opencv ${OpenCV_LIBS})
------------------------orb_slam3----------------------------
//运行双目数据集MH_01_easy.zip解压 文件目录结构/ORB_SLAM3/Datasets/MH01/mav0
cd ORB_SLAM3/
./Examples/Stereo/stereo_euroc ./Vocabulary/ORBvoc.txt ./Examples/Stereo/EuRoC.yaml ./Datasets/MH01 ./Examples/Stereo/EuRoC_TimeStamps/MH01.txt dataset-MH01_sterego
ros单目运行命令
rosrun ORB_SLAM3 Mono ./Vocabulary/ORBvoc.txt ./Examples/Monocular/EuRoC.yaml
roslaunch astra_camera astra_pro.launch //启动rgbd摄像头
//启动rgbd slam3
rosrun ORB_SLAM3 RGBD ./Vocabulary/ORBvoc.txt ./Examples_old/ROS/ORB_SLAM3/Asus.yaml
roslaunch astra_camera astra_pro.launch
rosservice call /camera/set_uvc_mirror "{data: true}" //可以为彩色图设置镜像
ros2 run ros1_bridge dynamic_bridge --bridge-all-topics
ros2 run orbslam3 rgbd ~/ORB_SLAM3/Vocabulary/ORBvoc.txt ~/ORB_SLAM3/Examples/RGB-D/TUM1.yaml //启动rgbd
----------------------usb------------------------
为什么普通账户会没有权限访问ttyUSB设备?
ls -l /dev/ttyUSB0
crwxrwxrwx 1 root dialout 188, 0 6月 20 18:06 /dev/ttyUSB0
ttyS设备的用户主是root,而所属的组是dialout,owner和group有相同的rw权限的,others没有任何权限
groups 用户名 查看用户所属的组并不在dialout组里面,只要加入这个组就有了usb权限
//加入dialout组命令:
sudo usermod -a -G dialout 用户名
在用groups命令查看就已经加入组中了,之后就可以自由的使用usb设备了。
ubuntu20.04的 brltty 导致 USB 转串口连接失败
sudo dmesg | grep brltty
[ 0.077725] printk: console [tty0] enabled //控制台[tty0]已启用
sudo apt remove brltty //删除brltty
ls /dev/ttyUSB*
/dev/ttyUSB0
usb绑定端口号,注意端口占用
lsusb 查看自己的USB串口ID
udevadm info --attribute-walk --name=/dev/ttyUSB0查看ttyUSB0的KERNELS硬件端口号
usb串口绑定
sudo gedit /etc/udev/rules.d/usb.rules //打开usb规则
KERNELS=="3-1:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="ttyTHS1" //串口起别名
sudo udevadm control --reload-rules && sudo udevadm trigger//不重启电脑配置usb设备
--------------------------untntu安装后设置-------------------
修改开机启动顺序
/etc/default内打开终端 sudo vim grub 修改GRUB_DEFAULT=4
保存退出之后,执行“sudo update-grub”来重新生成GRUB启动配置项
sudo vi /etc/systemd/logind.conf 修改关闭笔记本显示器不休眠
修改以下配置:HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
重启服务:sudo service systemd-logind restart
-------------------------设置时间-------------------------------
timedatectl 显示时间模式
sudo timedatectl set-local-rtc 1 修改时间模式
sudo hwclock --localtime --systohc 把修改的模式写入系统
---------------------------vs code 使用-----------------------
安装插件
Python C++ xml 中文插件
远程使用vscode
vscode 插件商店搜索ssh Remote—SSH并安装
F1输入Remote-SSH-Settings,设置Remote.SSH:Show Login Terminal为true
F1输入Remote-SSH选择Remote-SSH:Connect to Host… ----->选择add NEW SSH Host… ----->输入 your_name@server_ip ----->选择一个config(之后会出来配置config的信息,Host是自己给这份配置文件起的名字,HostName是远程主机的IP地址,User是登录名),之后输入密码即可登陆。
vscode包含路径方框内加入
${workspaceFolder}/**
/opt/ros/humble/**
-----------------------安装软件-----------------------
Ubuntu的软件包格式为deb。
sudo apt-get update 更新软件列表
sudo apt-get upgrade 更新软件
m@t:~/下载$ sudo dpkg -i weixin_2.1.1_amd64.deb 安装微信
https://pan.baidu.com/download 官网下载百度云盘的deb安装文件
sudo dpkg -i baidunetdisk_linux_2.0.1.deb 安装百度云盘
m@jt:~/下载$ sudo dpkg -i youdao-dict_6.0.0-ubuntu-amd64.deb 安装有道词典
sudo apt-get -f install 缺少依赖用次命令 重新在用上面安装命令
安装64位谷歌浏览器
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome-stable_current_amd64.deb
sudo apt install git 安装git
sudo apt install openssh-server 安装ssh
安装github内的软件
git clone https://github.com/6-robot/wpr_simulation.git
m@robot:~/下载$ sudo dpkg -i code_1.64.2-1644445741_amd64.deb 安装vscode
sudo apt-get install ros-foxy-usb-cam安装摄像头驱动
-----------------------------安装arduino-------------------------
https://blog.csdn.net/weixin_51331359/article/details/122289768 安装arduino一定要参考网页
tar -xvf arduino-1.8.19-linux64.tar.xz arduino解压文件
cd arduino-1.8.13 进入arduino文件夹打开终端
sudo ./install.sh 安装arduino
sudo usermod -a -G dialout m 把用户名m添加进dialout用户组 有使用usb权限 需要重启计算机
-------------------卸载软件----------------------------
软件卸载有两种方式:离线安装包的卸载(deb 文件格式卸载)
sudo dpkg –r 安装包名
在线安装包的卸载(apt-get 方式卸载)。
sudo apt-get remove --purge arduino 卸载arduino
sudo apt-get remove package 删除包
sudo apt-get remove package - - purge 删除包,包括删除配置文件等
sudo apt remove ros-foxy-gazebo-ros - - purge----------------aptitude 命令----------------------
aptitude与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具。与 apt-get 不同的是,aptitude在处理依赖问题上更佳一些。举例来说,aptitude在删除一个包时,会同时删除本身所依赖的包。这样,系统中不会残留无用的包,整个系统更为干净。
sudo apt-get install aptitude 安装aptitude
aptitude install pkgname 安装包
aptitude remove pkgname 删除包
aptitude purge pkgname 删除包及其配置文件
aptitude search string robot_state_publisher 搜索包 查找包
aptitude show pkgname 显示包的详细信息
-----------------------常用缩写简写----------------------------
GUI(Graphical User Interface)就是平常我们说的图形用户界面
CLI(Command-Line Interface)就是命令行界面了
API( Application Programming Interface)应用程序编程接口
RCL(ROS Client Library)ROS客户端库,其实就是ROS的一种API
rclpy(ROS Client Library python)python语言ros客户端库
rclcpp(ROS Client Library c++)c++语言ros客户端库
args (arguments) 表示位置参数
kwargs (keyword arguments) 表示关键字参数
SLAM(Simultaneous Localization And Mapping)同步定位与地图构建
cmd_vel (command velocity)命令 速度
SLAM是Simultaneous localization and mapping缩写,意为“同步定位与建图
APT(Advanced Packaging Tool)
bin为binary的简写
“dpkg ”是“Debian Packager ”的简写 为 “Debian” 专门开发的套件管理系统,方便软件的安装、更新及移除
SLAM是同步定位与地图构建(Simultaneous Localization And Mapping)的缩写
msg 英文全称message
rosdep其实是ros dependence,是管理包的依赖的
-i 是 install的意思
cd(changeDirectory) 命令语法
AMCL是Adaptive Monte Carlo Localization(也即是自适应蒙特卡洛定位)的简称,是基于多种蒙特卡洛融合算法在ROS/ROS2系统中的一种实现
exe executablefile 即可执行文件
STL standard template library 标准模板库
int,它是单词integer
char,它是单词character(字符)的缩写
const是constant的缩写,意思是“恒定不变的” - 1 安装
毛哥成山轮胎机油保养 发布的最新帖子
-
打开终端显示not found: "/opt/ros/foxy/share/slam_toolbox/local_setup.bash"
每次打开终端都显示not found: "/opt/ros/foxy/share/slam_toolbox/local_setup.bash",虽然对程序运行没有影响,但是很烦人,有人知道在哪里设置吗?翻遍网页也没有找到哪个文件影响了终端
-
串口设备断电提示代码怎么写呢,有知道的吗?
我的速控板有个电源开关,用的是usb转串口连接,启动速控板节点launch文件,显示启动正常,即使给速控板关闭电源,也没有错误提示,怎样加个提示电源已关闭的提示代码呢?
bool JtbotFocDriver::ReadFormSerial() // 读串口 { if (Robot_Serial.available()) { rxdata = Robot_Serial.read(Robot_Serial.available()); if (rxdata.size() == sizeof(JtbotFeedback)) { memcpy(&Feedback, rxdata.c_str(), sizeof(JtbotFeedback)); uint16_t checksum = (uint16_t)(Feedback.start ^ Feedback.rpmR ^ Feedback.rpmL ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.curL_DC ^ Feedback.curR_DC); if ((Feedback.start == START_FRAME) && (checksum == Feedback.checksum)) return true; else return false; } else { RCLCPP_INFO(this->get_logger(), "速控板读取数据失败22222"); return false; } } else { RCLCPP_INFO(this->get_logger(), "速控板读取数据失败11111"); return false; } }
我加的: RCLCPP_INFO(this->get_logger(), "速控板读取数据失败11111"); 这段代码只要开机就一直刷屏。
RCLCPP_INFO(this->get_logger(), "速控板读取数据失败22222"); 这段代码加的位置不管速控板是否开机根本就不提示,说明加的位置不对。
串口初始化的位置我也加了提示,只是没有插usb口有错误提示,如果usb口插好了速控板开不开电源都提示初始化成功。/**打开串口设备**/ try { Robot_Serial.setPort(port_name_); Robot_Serial.setBaudrate(baud_rate_); serial::Timeout to = serial::Timeout::simpleTimeout(2000); Robot_Serial.setTimeout(to); Robot_Serial.open(); } catch (serial::IOException &e) { RCLCPP_INFO(this->get_logger(), "foc速控板打开失败,请检查串口是否连接"); } if (Robot_Serial.isOpen()) { RCLCPP_INFO(this->get_logger(), "速控板串口打开成功"); } else { } }
懂c++的朋友给指点一下
速控板完整代码#include "jtbot_foc_driver/jtbot_foc_driver.h" using namespace std::chrono_literals; JtbotFocDriver::JtbotFocDriver() : Node("jtbot_foc_driver"), odom_theta_(0), x_pos_(0), y_pos_(0) // 构造函数,初始化成员变量 { wheel_diameter_ = WHEEL_DIAMETER; // 轮子直径 wheel_circumference_ = PI * wheel_diameter_; // 轮子周长 max_rpm_ = MAX_RPM; // 轮子最大转速 wheels_x_distance_ = FR_WHEELS_DISTANCE; // 2轮差速 前后轮子距离 0 wheels_y_distance_ = LR_WHEELS_DISTANCE; // 左右轮子距离 now_ = now(); declare_parameter("port_name", std::string("/dev/ttyTHS1")); // 根据实际端口修改 get_parameter("port_name", port_name_); declare_parameter("baud_rate", 115200); get_parameter("baud_rate", baud_rate_); // 发布电池电量 battery_pub_ = this->create_publisher<std_msgs::msg::Float32>("battery", 10); // 定时10毫秒发布电池和速度 odom 和 tf2 topic_timer_ = this->create_wall_timer(10ms, std::bind(&JtbotFocDriver::RosNodeTopicCallback, this)); // 接收速度话题 回调函数发布控制命令 velocity_sub_ = this->create_subscription<geometry_msgs::msg::Twist>("cmd_vel", 10, std::bind(&JtbotFocDriver::cmd_vel_callback, this, std::placeholders::_1)); // odom_publisher_ = this->create_publisher<nav_msgs::msg::Odometry>("odom_diff", 20); //创建odom发布者 odom_publisher_ = this->create_publisher<nav_msgs::msg::Odometry>("odom", 20); // 创建odom发布者 odom_transform_broadcaster_ = std::make_shared<tf2_ros::TransformBroadcaster>(this); // 创建tf2发布者 last_odom_time_ = now(); odom_.header.frame_id = "odom"; // odom_.child_frame_id = "base_footprint"; odom_.child_frame_id = "base_link"; odom_transform_.header.frame_id = "odom"; // odom_transform_.child_frame_id = "base_footprint"; odom_transform_.child_frame_id = "base_link"; /**打开串口设备**/ try { Robot_Serial.setPort(port_name_); Robot_Serial.setBaudrate(baud_rate_); serial::Timeout to = serial::Timeout::simpleTimeout(2000); Robot_Serial.setTimeout(to); Robot_Serial.open(); } catch (serial::IOException &e) { RCLCPP_INFO(this->get_logger(), "foc速控板打开失败,请检查串口是否连接"); } if (Robot_Serial.isOpen()) { RCLCPP_INFO(this->get_logger(), "速控板串口打开成功"); } else { } } JtbotFocDriver::~JtbotFocDriver() { Robot_Serial.close(); } void JtbotFocDriver::RosNodeTopicCallback() // ros节点话题回调 { if (true == ReadFormSerial()) { publisherBattery(); // 发布电压 低于33伏发布充电警告 PublisherOdom(); // 发布odom } } bool JtbotFocDriver::ReadFormSerial() // 读串口 { if (Robot_Serial.available()) { rxdata = Robot_Serial.read(Robot_Serial.available()); if (rxdata.size() == sizeof(JtbotFeedback)) { memcpy(&Feedback, rxdata.c_str(), sizeof(JtbotFeedback)); // printf("Feedbac左轮转速 %hd 右轮转速 %hd 电压 %lf 主板温度 %lf\n",Feedback.rpmL,Feedback.rpmR,double(Feedback.batVoltage)/100,double(Feedback.boardTemp)/10); uint16_t checksum = (uint16_t)(Feedback.start ^ Feedback.rpmR ^ Feedback.rpmL ^ Feedback.batVoltage ^ Feedback.boardTemp ^ Feedback.curL_DC ^ Feedback.curR_DC); if ((Feedback.start == START_FRAME) && (checksum == Feedback.checksum)) return true; else return false; } else { RCLCPP_INFO(this->get_logger(), "速控板读取数据失败22222"); return false; } } else { RCLCPP_INFO(this->get_logger(), "速控板读取数据失败11111"); return false; } } /*cmd_vel Subscriber的回调函数*/ void JtbotFocDriver::cmd_vel_callback(const geometry_msgs::msg::Twist::SharedPtr twist_msg) { SetVelocity(twist_msg->linear.x, twist_msg->linear.y, twist_msg->angular.z); } /*底盘速度发送函数*/ void JtbotFocDriver::SetVelocity(double x, double y, double angular_z) { calculateRPM(x, y, angular_z); // 把速度映射为foc波形 int16_t mSpeedL = map(req_rpm.motor1, -max_rpm_, max_rpm_, -FOC_MAX_PWM, FOC_MAX_PWM); int16_t mSpeedR = map(req_rpm.motor2, -max_rpm_, max_rpm_, -FOC_MAX_PWM, FOC_MAX_PWM); // 根据收到的cmd_vel计算左右轮的速度,装填数据,写人串口 Command.start = (uint16_t)START_FRAME; Command.mSpeedR = (uint16_t)mSpeedR; Command.mSpeedL = (uint16_t)mSpeedL; Command.checksum = (uint16_t)(Command.start ^ Command.mSpeedR ^ Command.mSpeedL); if (Robot_Serial.write((uint8_t *)&Command, sizeof(Command)) <= 0) { RCLCPP_INFO(this->get_logger(), "速控板写入速度控制数据失败,请检查"); } } void JtbotFocDriver::publisherBattery() // 发布显示电压 { if ((now() - now_).seconds() > 1 / BATTERY_RATE) { raw_battery_msg.data = (float)Feedback.batVoltage / 100; if (raw_battery_msg.data < 35) { RCLCPP_WARN(this->get_logger(), "当前电压: %f ,电压偏低,请充电!!", raw_battery_msg.data); battery_pub_->publish(raw_battery_msg); now_ = now(); } } } void JtbotFocDriver::PublisherOdom() // 发布odom { getVelocities(Feedback.rpmL, Feedback.rpmR); // 获取速度,数据填充到vel结构体 rclcpp::Time current_time = now(); odom_.header.stamp = current_time; // x线速度 auto linear_velocity_x_ = vel.linear_x; // y线速度 auto linear_velocity_y_ = vel.linear_y; // 角速度 auto angular_velocity_z_ = vel.angular_z; rclcpp::Duration vel_dt_ = current_time - last_odom_time_; last_odom_time_ = current_time; double delta_heading = angular_velocity_z_ * vel_dt_.nanoseconds() / 1e9; // radians double delta_x = (linear_velocity_x_ * cos(odom_theta_)) * vel_dt_.nanoseconds() / 1e9; // m double delta_y = (linear_velocity_x_ * sin(odom_theta_)) * vel_dt_.nanoseconds() / 1e9; // m x_pos_ += delta_x; y_pos_ += delta_y; odom_theta_ += delta_heading; tf2::Quaternion odom_q; // 声明四元数 odom_q.setRPY(0, 0, odom_theta_); // 欧拉角换算四元数 // 相对于父坐标系位置 odom_.pose.pose.position.x = x_pos_; odom_.pose.pose.position.y = y_pos_; odom_.pose.pose.position.z = 0.0; // 相对于父坐标系姿态四元数 odom_.pose.pose.orientation.x = odom_q.x(); odom_.pose.pose.orientation.y = odom_q.y(); odom_.pose.pose.orientation.z = odom_q.z(); odom_.pose.pose.orientation.w = odom_q.w(); // 姿态协方差 // odom_.pose.covariance[0] = 0.001; // odom_.pose.covariance[7] = 0.001; // odom_.pose.covariance[35] = 0.001; // 相对于子坐标系线速度和角速度 odom_.twist.twist.linear.x = linear_velocity_x_; odom_.twist.twist.linear.y = linear_velocity_y_; odom_.twist.twist.angular.z = angular_velocity_z_; // 协方差分为静止和运动: // pose: // if(linear_velocity_x_==0){ // //pose静止: // odom_.pose.covariance[0] = 1e-9; // odom_.pose.covariance[7] = 1e-3; // odom_.pose.covariance[8] = 1e-9; // odom_.pose.covariance[14] = 1e6; // odom_.pose.covariance[21] = 1e6; // odom_.pose.covariance[28] = 1e6; // odom_.pose.covariance[35] = 1e-9; // //twist静止: // odom_.twist.covariance[0] = 1e-9; // odom_.twist.covariance[7] = 1e-3; // odom_.twist.covariance[8] = 1e-9; // odom_.twist.covariance[14] = 1e6; // odom_.twist.covariance[21] = 1e6; // odom_.twist.covariance[28] = 1e6; // odom_.twist.covariance[35] = 1e-9; // } // else{ // //pose运动: // odom_.pose.covariance[0] = 1e-3; // odom_.pose.covariance[7] = 1e-3; // odom_.pose.covariance[8] = 0.0; // odom_.pose.covariance[14] = 1e6; // odom_.pose.covariance[21] = 1e6; // odom_.pose.covariance[28] = 1e6; // odom_.pose.covariance[35] = 1e3; // //twist运动: // odom_.twist.covariance[0] = 1e-3; // odom_.twist.covariance[7] = 1e-3; // odom_.twist.covariance[8] = 0.0; // odom_.twist.covariance[14] = 1e6; // odom_.twist.covariance[21] = 1e6; // odom_.twist.covariance[28] = 1e6; // odom_.twist.covariance[35] = 1e3; // } odom_.header.stamp = now(); odom_publisher_->publish(odom_); // printf("odom_.pose x y z %f %f %f \n",x_pos_,y_pos_,odom_theta_); // printf("odom_.twist x y z %f %f %f \n",linear_velocity_x_,linear_velocity_y_,angular_velocity_z_); odom_transform_.header.stamp = last_odom_time_; odom_transform_.transform.translation.x = x_pos_; odom_transform_.transform.translation.y = y_pos_; odom_transform_.transform.rotation.x = odom_q.x(); odom_transform_.transform.rotation.y = odom_q.y(); odom_transform_.transform.rotation.z = odom_q.z(); odom_transform_.transform.rotation.w = odom_q.w(); // odom_transform_broadcaster_->sendTransform(odom_transform_); //开odom imu融合需要关闭/tf话题 // printf("now last_odom_time_%ld %ld %ld\n",now(),current_time,last_odom_time_); } // 计算转速 void JtbotFocDriver::calculateRPM(float linear_x, float linear_y, float angular_z) { float linear_vel_x_mins; float linear_vel_y_mins; float angular_vel_z_mins; float tangential_vel; float x_rpm; float y_rpm; float tan_rpm; // 转换米/秒 至 米/分 linear_vel_x_mins = linear_x * 60; linear_vel_y_mins = linear_y * 60; // 转换 rad/秒 to rad/分 angular_vel_z_mins = angular_z * 60; tangential_vel = angular_vel_z_mins * ((wheels_x_distance_ / 2) + (wheels_y_distance_ / 2)); x_rpm = linear_vel_x_mins / wheel_circumference_; y_rpm = linear_vel_y_mins / wheel_circumference_; tan_rpm = tangential_vel / wheel_circumference_; req_rpm.motor1 = int16_t(x_rpm - y_rpm - tan_rpm); req_rpm.motor1 = constrain(req_rpm.motor1, -max_rpm_, max_rpm_); // front-right motor req_rpm.motor2 = -int16_t(x_rpm + y_rpm + tan_rpm); req_rpm.motor2 = constrain(req_rpm.motor2, -max_rpm_, max_rpm_); } void JtbotFocDriver::getVelocities(int rpm1, int rpm2) // 获取速度,数据填充到vel结构体 { float average_rps_x; // float average_rps_y; float average_rps_a; // 将平均每分钟转数转换为每秒转数,小车向前走左轮为正,右轮为负 average_rps_x = ((float)(rpm1 - rpm2) / 2) / 60; // RPM vel.linear_x = average_rps_x * wheel_circumference_; // m/s // 将y轴上的平均每分钟转数转换为每秒转数 // average_rps_y = ((float)(-rpm1 + rpm2) / 2) / 60; // RPM vel.linear_y = 0; // 将平均每分钟转数转换为每秒转数 average_rps_a = ((float)(rpm1 + rpm2) / 2) / 60; vel.angular_z = -(average_rps_a * wheel_circumference_) / ((wheels_x_distance_ / 2) + (wheels_y_distance_ / 2)); // rad/s } // 速度映射到foc波形 int16_t JtbotFocDriver::map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } int main(int argc, char *argv[]) { rclcpp::init(argc, argv); auto driver = std::make_shared<JtbotFocDriver>(); rclcpp::spin(driver); rclcpp::shutdown(); return 0; }
-
RE: 导航实物部署
@3568485143 如果没有imu 最好先不要用融合定位,融合的话底盘发出的/odom需要修改,假设修改成/odom_diff, 融合生成的话题也需要映射
remappings=[('/odometry/filtered','odom'),],
还要配置ekf.yaml文件,难度会增大很多,导致你很难判断哪里有问题 -
RE: 请问ros2 run和ros2 launch启动同一个节点的启动效果不同是什么原因呢?
@Lorry 可以了
KERNELS=="3-2.3:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="ttyimu",
以前弄了好多次,不行,刚刚重新试了一下,可以了。 -
RE: 请问ros2 run和ros2 launch启动同一个节点的启动效果不同是什么原因呢?
@Lorry 我试遍了网上给usb端口改别名的方法,就是不生效,只能把imu第一个插上选/dev/ttyUSB0,你有经验吗?
-
RE: 请问ros2 run和ros2 launch启动同一个节点的启动效果不同是什么原因呢?
@小鱼 c++还是有点驾驭不了,源码在这
链接文本
鱼总有时间帮我分析一下哪里有问题,现在这个程序用launch启动逻辑是不正常的,只能用ros2 run 启动,还有这个imu我用尽了各种办法都不能固定usb端口别名,只能是先插这个imu 它的端口号用ttyUSB0
usb.rulesKERNELS=="1-1.2:1.0", MODE:="0777", GROUP:="dialout",SYMLINK+="wheeltec_laser" KERNELS=="3-1:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="ttyTHS1" SUBSYSTEM=="usb", ATTR{idProduct}=="0403", ATTR{idVendor}=="2bc5", MODE:="0666", OWNER:="root", GROUP:="video", SYMLINK+="astra_pro" SUBSYSTEM=="usb", ATTR{idProduct}=="0501", ATTR{idVendor}=="2bc5", MODE:="0666", OWNER:="root", GROUP:="video", SYMLINK+="astrauvc" KERNEL=="ttyUSB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0777",GROUP:="dialout", SYMLINK+="ttyimu"
其他像雷达 摄像头 底盘驱动端口都生效了,这个ttyimu就是死活不生效,现在只能用/dev/ttyUSB0
-
RE: 导航实物部署
@3568485143 我这段时间也一直在研究实体机器人导航这一块,你的机器人开启imu了吗,如果没有开启先不用Node(
package='robot_localization',
executable='ekf_node',
这个节点,这个节点是融合里程计和imu的,跑通了在把这个节点加上,先用最简单的模型跑通导航,你可以参考一下我的学习记录
链接文本,
我也遇到了很多问题,我们可以一起探讨