本制作采用了:上位机----tx2(ubuntu16.04)
下位机----Arduino 2560
传感器-----思岚rplidar A2
代码见:https://github.com/crjxixixi/cleaner_robot1.git
现在主要对自己的上位机代码进行一些解释:
建立地图的方式有两种:gmapping算法与 hector算法
区别:Gmapping 算法在建立地图时需要机器人雷达的扫描信息与里程计信息
Hector 算法只需要机器人的雷达扫描信息
本实验采取的是hector进行建图:
(1)准备工作:安装hector_slam库
sudo apt-get install ros-kinetic-hector-slam
(2) 创建 hector.launch(本代码在/src/mrobot_navigation/launch)
<launch>
<node pkg="hector_mapping" type="hector_mapping" name="hector_mapping" output="screen">
<!-- Frame names -->
<param name="pub_map_odom_transform" value="true"/>
<param name="map_frame" value="map" />
<param name="base_frame" value="base_link" />
<param name="odom_frame" value="base_link" />
<!-- Tf use -->
<param name="use_tf_scan_transformation" value="true"/>
<param name="use_tf_pose_start_estimate" value="false"/>
<!-- Map size / start point -->
<param name="map_resolution" value="0.05"/>
<param name="map_size" value="512"/>
<param name="map_start_x" value="0.5"/>
<param name="map_start_y" value="0.5" />
<param name="laser_z_min_value" value = "-1.0" />
<param name="laser_z_max_value" value = "1.0" />
<param name="map_multi_res_levels" value="2" />
<param name="map_pub_period" value="2" />
<param name="laser_min_dist" value="0.4" />
<param name="laser_max_dist" value="5.5" />
<param name="output_timing" value="false" />
<param name="pub_map_scanmatch_transform" value="true" />
<!--<param name="tf_map_scanmatch_transform_frame_name" value="scanmatcher_frame" />-->
<!-- Map update parameters -->
<param name="update_factor_free" value="0.4"/>
<param name="update_factor_occupied" value="0.7" />
<param name="map_update_distance_thresh" value="0.2"/>
<param name="map_update_angle_thresh" value="0.06" />
<!-- Advertising config -->
<param name="advertise_map_service" value="true"/>
<param name="scan_subscriber_queue_size" value="5"/>
<param name="scan_topic" value="scan"/>
</node>
<node pkg="tf" type="static_transform_publisher" name="base_to_laser_broadcaster" args="0 0 0 0 0 0 /base_link /laser 100"/>
<node pkg="rviz" type="rviz" name="rviz"
args="-d $(find hector_slam_launch)/rviz_cfg/mapping_demo.rviz"/>
</launch>
若遇到有不能启动则根据提示安装相应的包就可运行,随着机器人的移动可以在rviz可视化界面中看到你的栅格地图构建的情况。
(3)地图保存
在地图保存之前,需要安装map_server包,在终端中输入:
sudo apt-get install ros-kinetic-map-server
然后,保存图形:
rosrun map_server map_saver -f ~/my_map
~处可以修改为你要存放的地址,本操作将地址保存在根目录下。
由于每个人的机器人外形都不相同,大家可以自己去编写适合自己机器人的urdf,大家可以参考 urdf古月居
在本实验中,由于下位机是采取的Arduino,则在开发时可以将Arduino定义为一个结点来收发话题,从而方便开发(若使用的是stm32进行开发的则需要自己编写串口通信)
1.准备工作
(1)若想要学习如何将Arduino定义为一个结点的大家可以到创客智造中找到相应的教程:
https://www.ncnynl.com/archives/201701/1215.html
(2)Arduino IDE的安装
可以参考教程:https://jingyan.baidu.com/article/219f4bf7e45df3de442d388e.html
(3)ROS相应的导航包安装
2.编写相应的launch文件(可见代码/src/mrobot_navigation/mrobot_nav.launch)
<launch>
<param name="use_sim_time" value="false" />
<arg name="use_map_topic" default="false"/>
<arg name="scan_topic" default="scan"/>
<!-- 配置雷达 -->
<node name="rplidarNode" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" type="string" value="/dev/ttyUSB0"/>
<param name="serial_baudrate" type="int" value="115200"/>
<param name="frame_id" type="string" value="laser"/>
<param name="inverted" type="bool" value="false"/>
<param name="angle_compensate" type="bool" value="true"/>
</node>
<!--地图信息-->
<arg name="map_file" default="/home/xt/my_map.yaml"/>
<node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" />
<!--机器人 move_base -->
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="false">
<rosparam file="$(find mrobot_navigation)/config/mrobot1/costmap_common_params.yaml" command="load" ns="global_costmap" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/costmap_common_params.yaml" command="load" ns="local_costmap" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/local_costmap_params.yaml" command="load" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/global_costmap_params.yaml" command="load" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/base_local_planner_params.yaml" command="load" />
</node>
<include file="$(find mrobot_navigation)/launch/amcl.launch" />
<!-- 设置坐标-->
<node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.0 0.0 0.0 0.0 0.0 0.0 /base_link /laser 40" />
<!-- 运行rviz -->
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find mrobot_navigation)/rviz/nav.rviz"/>
</launch>
根据自己的传感器进行相应的配置,本实验中用的是思岚的rplidar A2雷达,所以该launch文件首先对雷达进行了配置
< laser >
<node name="rplidarNode" pkg="rplidar_ros" type="rplidarNode" output="screen">
<param name="serial_port" type="string" value="/dev/ttyUSB0"/>
<param name="serial_baudrate" type="int" value="115200"/>
<param name="frame_id" type="string" value="laser"/>
<param name="inverted" type="bool" value="false"/>
<param name="angle_compensate" type="bool" value="true"/>
设置雷达的串口号、波特率等一些参数,在使用雷达的时候需要给串口权限(根据自己的串口号),本实验中用的是ttyUSB0则给权限如下:
sudo chmod 777 /dev/ttyUSB0
接着加载你刚建好的地图信息:
< map >
<arg name="map_file" default="/home/xt/my_map.yaml"/>
<node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" />
将default后面的参数为你地图所在的路径
< move_base > 主要配置机器人的移动时的一些参数(如速度、避障、地图膨胀、路径规划算法)等
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="false">
<rosparam file="$(find mrobot_navigation)/config/mrobot1/costmap_common_params.yaml" command="load" ns="global_costmap" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/costmap_common_params.yaml" command="load" ns="local_costmap" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/local_costmap_params.yaml" command="load" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/global_costmap_params.yaml" command="load" />
<rosparam file="$(find mrobot_navigation)/config/mrobot1/base_local_planner_params.yaml" command="load" />
</node>
</node>
其中base_local_planner_params.yaml、costmap_common_params.yaml、global_costmap_params.yaml、local_costmap_params.yaml文件各参数的配置及其各参数的含义可以看此教程https://www.guyuehome.com/28164
< amcl >
<node pkg="amcl" type="amcl" name="amcl" clear_params="true">
<param name="use_map_topic" value="$(arg use_map_topic)"/>
<!-- translation std dev, m -->
<param name="global_frame_id" value="/map" />
<param name="initial_pose_x" value="0.0"/>
<param name="initial_pose_y" value="0.0"/>
<param name="initial_pose_a" value="0.0"/>
<param name="initial_cov_xx" value="0.5*0.5"/>
<param name="initial_cov_yy" value="0.5*0.5"/>
<param name="initial_cov_aa" value="(π/12)*(π/12)"/>
<param name="odom_alpha3" value="0.2"/>
<param name="odom_alpha4" value="0.2"/>
<param name="laser_z_hit" value="0.5"/>
<param name="laser_z_short" value="0.05"/>
<param name="laser_z_max" value="0.05"/>
<param name="laser_z_rand" value="0.5"/>
<param name="laser_sigma_hit" value="0.2"/>
<param name="laser_lambda_short" value="0.1"/>
<param name="laser_model_type" value="likelihood_field"/>
<param name="initial_pose_x" value="0.0"/>
<param name="odom_model_type" value="diff"/>
<param name="odom_alpha5" value="0.1"/>
<param name="gui_publish_rate" value="10.0"/>
<param name="laser_max_beams" value="60"/>
<param name="laser_max_range" value="12.0"/>
<param name="min_particles" value="500"/>
<param name="max_particles" value="2000"/>
<param name="kld_err" value="0.05"/>
<param name="kld_z" value="0.99"/>
<param name="odom_alpha1" value="0.2"/>
<param name="odom_alpha2" value="0.2"/>
<!-- <param name="laser_model_type" value="beam"/> -->
<param name="laser_likelihood_max_dist" value="2.0"/>
<param name="update_min_d" value="0.25"/>
<param name="update_min_a" value="0.2"/>
<param name="odom_frame_id" value="odom"/>
<param name="base_frame_id" value="base_link"/>
<param name="resample_interval" value="1"/>
<!-- Increase tolerance because the computer can get quite busy -->
<param name="transform_tolerance" value="1.0"/>
<param name="recovery_alpha_slow" value="1.0"/>
<param name="recovery_alpha_fast" value="0.0"/>
<remap from="scan" to="$(arg scan_topic)"/>
</node>
此结点是用于发布机器人的定位信息的功能,详细情况可以参考:http://wiki.ros.org/amcl,大致来说,amcl需要订阅机器人的消息有 1.传感器的信息 2.tf变换 3.地图信息 4.机器人的初始位置,从而通过这些信息来发布 1.机器人的位姿 2.粒子云 3./tf变换(/map–>/odom),这样机器人就能实时的掌握自己所处的位置,并通过mover_base来进行导航。
< rviz >
<node pkg="rviz" type="rviz" name="rviz" args="-d $(find mrobot_navigation)/rviz/nav.rviz"/>
打开rviz可视化工具可以看到机器人在地图上的位置,与导航算法所规划出来的路径。
2.导航操作
导航前需要使用2D Post estimate对机器人位姿进行初始化,使得机器人雷达扫描点与之前所建地图尽可能重合。初始点的好坏对机器人导航效果有着一定的影响。
使用2D NAV Goal点击地图即可为机器人设置导航目标点,机器人会自动规划出行进路线,机器人会循着路径到达设置的地点。
文章浏览阅读1.1k次。1、现象:postgresql源表数据量:抽取到HDFS上和Hive之后数据量:2、原因:使用sqoop从pg库导出数据至HDFS或Hive时,如果数据中包含Hive指定的列分隔符,如”\001”或”\t”,那么在Hive中就会导致数据错位;如果数据中包含换行符”\n”,那么就会导致原先的一行数据,在Hive中变成了两行或多行数据,导致数据量增多。正常的:3、解决:在sqoop执行import导入命令时添加参数–hive-drop-import-delims,作用是在导入时从字符串字_hive 平台抽取pg库数据
文章浏览阅读1.5k次。docker pull ubuntusudo modprobe nf_conntrack_pptpecho nf_conntrack_pptp | sudo tee /etc/modules-load.d/pptp.confdocker run -i -t --privileged=true ubuntu:latest /bin/bashapt-get -y updateapt-get -y_docker pptp 807
文章浏览阅读1.5k次,点赞3次,收藏9次。UE4中自定义用于sequence的变量和函数https://zhuanlan.zhihu.com/p/136962130ue4进化了sequence这个系统,每个版本都在进化,使得这个工具越来越好用,好用到我们甚至我们在做游戏的时候,任意的过场都可以拿他来制作,可以说是美术的利器。绝大部分美术在短时间内就能学会ue4的sequence并用它做出绚烂的画面,但是,这只限制与一般的单机游戏的过场,如果我们希望把它做成游戏里的事件的过场,比如触发事件后的表现,就有不少欠缺了。最主要的是,因为角色在游_蓝图 操作 sequence
文章浏览阅读341次。怎样优化一人四机搬运流程,不会出现workerpool手上有工件在工位前发呆,导致后工位的停止_plant工人
文章浏览阅读6k次。问题:在使用okhttp下载文件的时候拿到的文件长度为-1解决思路1.看服务器返回的请求头是否含有Content-Lengthcmd 打开命令窗口输入 curl -i +下载链接窗口显示 connect-length 是有数值的2.看返回的content-typecontent-type类型https://www.runoob.com/http/http-content-type.html第一个返回text/plain; charset=utf-8 表示文本类型..._解决okhttp content-length -1
文章浏览阅读3.4k次。首先在demo中是没有问题的,然后集成到正式项目中就报了这个错,反复对比了好几次配置都一样的(有种情况是集成了但是不使用也会报错没找到类xxx)。先Googlegoogle发现该项目的issues里面也有很多人遇到这个问题。https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx/issues/101h..._aspectjtools zip file is empty
文章浏览阅读471次,点赞7次,收藏4次。面向对象编程(二)文章目录面向对象编程(二)五、类的方法1.在类之外定义方法2.this六、 动态对象七、 公有和私有关注作者五、类的方法类中的程序也称为方法,也就是在类的作用域内定义的内部task或者function。类中的方法默认使用自动存储,所以不必担心忘记使用automatic修饰符。1.在类之外定义方法一条值得称道的规则是,你应当限制代码段的长度在一页范围内以保证其可读性。该规则用于函数或任务时你能并不感到陌生,但是它同样适用于类。如果你可以在一屏内读到类的所有的东西,那么理解该类就会变_sv在类之外定义方法
文章浏览阅读1.6k次。xadmin使用formfield_for_dbfield函数过滤下拉表单环境:Django 2.0.7 xadmin 2.0.1需求:下拉表单显示的是模型的其他表项或者外键 # 重写formfield_for_dbfield,设计add和edit表单 def formfield_for_dbfield(self, db_field, **kwargs): i..._formfield_for_dbfield
文章浏览阅读77次。无论是对于准备参加校园招聘、社会招聘的同学,还是想在工作中持续提升技术能力的同学,深度地理解计算机硬件、Linux 内核底层原理都是非常重要的。我之前给大家分享技术主要是通过公众号、纸质出版书等途径。其中《深入理解Linux网络》入围了2022年中国开发者影响力IT图书榜单。新的一本讲 CPU 原理、进程调度、内存管理方面的书也已经审稿中,预计明年会出版。但图文的表达力还是有限,更多的读者希望我能...
文章浏览阅读4.2k次。看到一篇有用的文章 遂转载获取网页文件大小的方法:url = new URL("http://158.46.34.140/index1.jpg");HttpURLConnection httpconn = (HttpURLConnection)url.openConnection();int length=httpconn.getContentLength();_inputstream.available
文章浏览阅读2.5k次。XPath helper插件概述xPath Helper插件是什么? xPath helper是一款Chrome浏览器的开发者插件,安装了xPath helper后就能轻松获取HTML元素的 xPath,程序员就再也不需要通过搜索html源代码,定位一些id去找到对应的位置去解析网页了。XPath helper插件功能介绍google插件XPath Helper可以支持在网页点击元..._xpath helper 使用id定位
文章浏览阅读561次。我在网上查找了很多关于微信支付的案例很多但是部分讲的不是很细节,自己拿过来以后不知道如何去使用比较乱。我这几天研究了一下微信的支付v2的文档目前自己还是一个头脑简单的码农如果我哪里有啥不对的欢迎大家来指点一下,谢谢大家!!!!!!!!!!!!!我们都知道微信支付的app相关的接口是要封装好app传过来的相关参数数据打包给前端来唤起支付,其中最令人头疼的可能就是签名。好多人你不理解签名是怎么回事。其实理解了微信支付文档,其实一点也不难。签名就是客户端发数据给后台,后台打包下单参数签名一次,把返回的数据做处_微信下单时签名作用