ROS1云课→29如何借助导航实现走迷宫机器人

ROS1云课→28机器人代价地图配置

简述: 在这个项目中,将创建一个机器人,它将进入一个迷宫形式的房间,然后从另一个点离开房间。

详细: 在行业中,有些地方机器人可以收集加工过的物体并将这些物体放入仓库。所以这里在这个对象收集过程中,机器人需要进入机器加工区域,它应该从机器加工区域出来。机器人进入机器区域本质上类似于房间入口,机器人从机器区域出来也称为房间出口。  所以在这个项目中,将开发一个机器人应用程序,该应用程序应该在规定的入口位置进入房间,并通过测量距离来识别机器人进入路径和离开房间的物体/墙壁的距离与规定的出口地点。  为了寻找距离,通常使用激光雷达。通过将 激光测距仪集成到机器人中,将能够找到物体或墙壁的距离。这里需要借助ROS导航算法在STDR模拟器上进出房间。

案例方法也适用于机器人寻宝等竞赛场景。

涉及知识点多且杂。需要熟练掌握1-28节全部内容。 

全局路径规划知识点:

ROS1云课→20迷宫不惑之A*大法(一种虽古老但实用全局路径规划算法)

实际地图:

简化地图:

机器人:

参考文首链接。 

迷宫算法从基础到仿真。

未改进版本视频:

https://live.csdn.net/v/embed/2396

配置文件参考: 

代码语言:javascript
复制
export TURTLEBOT_STDR_MAP_FILE=/home/shiyanlou/Code/demo_ws/src/turtlebot_stdr/maps/maze.yaml
代码语言:javascript
复制
image: maze.png
resolution: 0.1
origin: [0.0, 0.0, 0.0]
occupied_thresh: 0.6
free_thresh: 0.3
negate: 0
代码语言:javascript
复制
<!--
  Turtlebot navigation simulation:
  - stdr
  - move_base
  - amcl
  - map_server
  - rviz view
 -->
<launch>
  <arg name="base"       default="$(optenv TURTLEBOT_BASE kobuki)"/>  <!-- create, rhoomba -->
  <arg name="stacks"     default="$(optenv TURTLEBOT_STACKS hexagons)"/>  <!-- circles, hexagons -->
  <arg name="3d_sensor"  default="$(optenv TURTLEBOT_3D_SENSOR kinect)"/>  <!-- kinect, asus_xtion_pro -->
  <arg name="laser_topic" default="robot0/laser_0"/> <!-- default laser topic in stdr for 1 robot -->
  <arg name="odom_topic" default="robot0/odom"/>
  <arg name="odom_frame_id" default="map"/>
  <arg name="base_frame_id" default="robot0"/>
  <arg name="global_frame_id" default="world"/>
  <!-- Name of the map to use (without path nor extension) and initial position -->
  <arg name="map_file"       default="$(env TURTLEBOT_STDR_MAP_FILE)"/>
  <arg name="initial_pose_x" default="0.5"/>
  <arg name="initial_pose_y" default="15.5"/>
  <arg name="initial_pose_a" default="0.0"/>
  <arg name="min_obstacle_height" default="0.0"/>
  <arg name="max_obstacle_height" default="5.0"/>

<!-- ******************** Stdr******************** -->
<include file="$(find stdr_robot)/launch/robot_manager.launch" />
<!-- Run STDR server with a prefedined map-->
<node pkg="stdr_server" type="stdr_server_node" name="stdr_server" output="screen" args="$(arg map_file)"/>
<!--Spawn new robot at init position 2 2 0-->
<node pkg="stdr_robot" type="robot_handler" name="(anon robot_spawn)&#34; args=&#34;add (find turtlebot_stdr)/robot/turtlebot.yaml (arg initial_pose_x) (arg initial_pose_y) 0"/>
<!-- Run Gui -->
<include file="$(find stdr_gui)/launch/stdr_gui.launch"/>
<!-- Run the relay to remap topics -->
<include file="$(find turtlebot_stdr)/launch/includes/relays.launch.xml"/>

<!-- ***************** Robot Model ***************** -->
<include file="$(find turtlebot_bringup)/launch/includes/robot.launch.xml">
<arg name="base" value="$(arg base)" />
<arg name="stacks" value="$(arg stacks)" />
<arg name="3d_sensor" value="$(arg 3d_sensor)" />
</include>
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher">
<param name="use_gui" value="true"/>
</node>

<!-- Command Velocity multiplexer -->
<node pkg="nodelet" type="nodelet" name="mobile_base_nodelet_manager" args="manager"/>
<node pkg="nodelet" type="nodelet" name="cmd_vel_mux" args="load yocs_cmd_vel_mux/CmdVelMuxNodelet mobile_base_nodelet_manager">
<param name="yaml_cfg_file" value="$(find turtlebot_bringup)/param/mux.yaml"/>
<remap from="cmd_vel_mux/output" to="mobile_base/commands/velocity"/>
</node>

<!-- ****** Maps ***** -->
<node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)">
<param name="frame_id" value="$(arg global_frame_id)"/>
</node>

<!-- ************** Navigation *************** -->
<include file="$(find turtlebot_navigation)/launch/includes/move_base.launch.xml">
<arg name="odom_topic" value="$(arg odom_topic)"/>
<arg name="laser_topic" value="$(arg laser_topic)"/>
<arg name="odom_frame_id" value="$(arg odom_frame_id)"/>
<arg name="base_frame_id" value="$(arg base_frame_id)"/>
<arg name="global_frame_id" value="$(arg global_frame_id)"/>
</include>

<!-- ***************** Manually setting some parameters ************************* -->
<param name="move_base/local_costmap/obstacle_layer/scan/min_obstacle_height" value="$(arg min_obstacle_height)"/>
<param name="move_base/local_costmap/obstacle_layer/scan/max_obstacle_height" value="$(arg max_obstacle_height)"/>
<param name="move_base/global_costmap/obstacle_layer/scan/min_obstacle_height" value="$(arg min_obstacle_height)"/>
<param name="move_base/global_costmap/obstacle_layer/scan/max_obstacle_height" value="$(arg max_obstacle_height)"/>

<!-- ************** AMCL ************** -->
<include file="$(find turtlebot_navigation)/launch/includes/amcl/amcl.launch.xml">
<arg name="scan_topic" value="$(arg laser_topic)"/>
<arg name="use_map_topic" value="true"/>
<arg name="odom_frame_id" value="$(arg odom_frame_id)"/>
<arg name="base_frame_id" value="$(arg base_frame_id)"/>
<arg name="global_frame_id" value="$(arg global_frame_id)"/>
<arg name="initial_pose_x" value="$(arg initial_pose_x)"/>
<arg name="initial_pose_y" value="$(arg initial_pose_y)"/>
<arg name="initial_pose_a" value="$(arg initial_pose_a)"/>
</include>

<!-- ********** Small tf tree connector between robot0 and base_footprint********* -->
<node name="tf_connector" pkg="turtlebot_stdr" type="tf_connector.py" output="screen"/>

<!-- **************** Visualisation **************** -->
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find turtlebot_stdr)/rviz/robot_navigation.rviz"/>

</launch>


代码语言:javascript
复制
shiyanlou:~/ $ history                                               [22:37:23]
1 gedit init.sh
2 chmod +x init.sh
3 ./init.sh
4 git clone https://gitcode.net/ZhangRelay/ros_book.git
5 cd ros_book
6 unzip turtlebot_simulator-melodic.zip
7 sudo apt install ros-kinetic-turtlebot-simulator
8 catkin_make
9 source devel/setup.zsh
10 export TURTLEBOT_STDR_MAP_FILE=/home/shiyanlou/Code/demo_ws/src/turtlebot_stdr/maps/maze.yaml
11 roslaunch turtlebot_stdr turtlebot_in_stdr.launch
12 source devel/setup.zsh
13 roslaunch turtlebot_stdr turtlebot_in_stdr.launch
14 export TURTLEBOT_STDR_MAP_FILE=/home/shiyanlou/Code/demo_ws/src/turtlebot_stdr/maps/hospital_section.yaml
15 export TURTLEBOT_STDR_MAP_FILE=/home/shiyanlou/Code/demo_ws/src/turtlebot_stdr/maps/hospital_section.yaml
16 roslaunch turtlebot_stdr turtlebot_in_stdr.launch
17 export TURTLEBOT_STDR_MAP_FILE=/home/shiyanlou/Code/demo_ws/src/turtlebot_stdr/maps/maze.yaml
18 roslaunch turtlebot_stdr turtlebot_in_stdr.launch
代码语言:javascript
复制
// Simple Maze Generator in C++ by Jakub Debski '2006

#include <time.h>
#include <vector>
#include <list>
using namespace std;

int main()
{
srand(time(0));

const int maze_size_x=80;
const int maze_size_y=25;
vector < vector < bool > > maze;
list < pair < int, int> > drillers;

maze.resize(maze_size_y);
for (size_t y=0;y<maze_size_y;y++)
maze[y].resize(maze_size_x);

for (size_t x=0;x<maze_size_x;x++)
for (size_t y=0;y<maze_size_y;y++)
maze[y][x]=false;

drillers.push_back(make_pair(maze_size_x/2,maze_size_y/2));
while(drillers.size()>0)
{
list < pair < int, int> >::iterator m,_m,temp;
m=drillers.begin();
_m=drillers.end();
while (m!=_m)
{
bool remove_driller=false;
switch(rand()%4)
{
case 0:
(*m).second-=2;
if ((*m).second<0 || maze[(*m).second][(*m).first])
{
remove_driller=true;
break;
}
maze[(*m).second+1][(*m).first]=true;
break;
case 1:
(*m).second+=2;
if ((*m).second>=maze_size_y || maze[(*m).second][(*m).first])
{
remove_driller=true;
break;
}
maze[(*m).second-1][(*m).first]=true;
break;
case 2:
(*m).first-=2;
if ((*m).first<0 || maze[(*m).second][(*m).first])
{
remove_driller=true;
break;
}
maze[(*m).second][(*m).first+1]=true;
break;
case 3:
(*m).first+=2;
if ((*m).first>=maze_size_x || maze[(*m).second][(*m).first])
{
remove_driller=true;
break;
}
maze[(*m).second][(*m).first-1]=true;
break;
}
if (remove_driller)
m = drillers.erase(m);
else
{
drillers.push_back(make_pair((*m).first,(*m).second));
// uncomment the line below to make the maze easier
// if (rand()%2)
drillers.push_back(make_pair((*m).first,(*m).second));

                       maze[(*m).second][(*m).first]=true; 
                       ++m; 
               } 
       } 

}

// Done
for (size_t y=0;y<maze_size_y;y++)
for (size_t x=0;x<maze_size_x;x++)
{
if (maze[y][x]==true)
printf(".");
else
printf("#");
}

return 0;
}

代码语言:javascript
复制
######.........#.#.......#.....#...#.....#.........#.#...#.#.......#.......#####
######.#.###.#.#.#.#######.#.#####.#.###.#.#.#####.#.###.#.#.#######.###########
.....#.#.#...#.#.........#.#.#.....#.###...#.#.....#.......#.......#.....#######
.#.#.###.#.#####.#.#.#######.#.#.#.#.#####################.#.###.#######.#######
.#.#.#...#...#...#.#...#.#.#.#.#.#.#.........#.....#...........#.#.............#
####.#.#######.#######.#.#.#.#.#.#######.#.#.#.#.#.#.#######.#######.#######.#.#
##...#...#####.#.#####.#...#...#.#...#.#.#.#...#.#...###...#.#.......#.......#.#
####.###.#####.#.#####.#.###.#.###.###.#.#.###.#########.#####.###.#############
.........###.#.....###.#...#.#.#.#.......#.#...#...#.#.#.#.......#.###...#.....#
########.###.#.#.#.###.#.#.###.#.#.#####.#.###.#.###.#.#.#.#.###.#####.###.#.###
.......#.....#.#.#.#...#.#...........#...#.#.....#.......#.#...#.#.........#...#
####.#.#.#####.#.###.#######.#######.###.#.#.###.#.#####.#.#####.#.#.#####.#####
...#.#.#.......#...#.....#.....#.#...#####.#...#.......#.#...#.....#...#.#.....#
##.###.#.#.#.###.#####.#.#####.#.#.#######.#####.#####.#.###.#.###.#####.#####.#
##...#...#.#.#.......#.#.....#...#.......#...#...#.....#.....#...#...........#.#
####.#.###########.###.#.###.#####.#######.###.###########.###.###.#####.###.###
####...###.....#...#.#.#...#...........###...#.###...#.###.###...#.....#.#.....#
####.#####.#######.#.###.###.#.#####.#.#############.#.###.#####.#####.#.###.###
####.........#.#...#.....#.#.#.#.....#.###.#...#.............#...#####.#...#...#
######.#.#####.#.###.#.#.#.###.#######.###.#.#####.###.#################.#######
######.#...#.#.....#.#.#.#...#...###...###.....#...#.......#########...#.......#
######.###.#.#####.#####.#.###.#.###.#.###.#.###.###.#####.#########.#########.#
######.#.#.#...###...#...#.#.#.#...#.#.....#.#.#...#.###...#########...#.......#
########.#.###.#######.#.#.#.###.#######.###.#.#####.###############.#.###.#####
########...###.........#.#.......#######.#.....#####.......#########.#.........#

路径规划研究的起源(如下为引用)

问题简介
18世纪初普鲁士的哥尼斯堡,有一条河穿过,河上有两个小岛,有七座桥把两个岛与河岸联系起来(如概述图)。有个人提出一个问题:一个步行者怎样才能不重复、不遗漏地一次走完七座桥,最后回到出发点。后来大数学家欧拉把它转化成一个几何问题——一笔画问题。他不仅解决了此问题,且给出了连通图可以一笔画的充要条件是:奇点的数目不是0个就是2个(连到一点的数目如果是奇数条,就称为奇点;如果是偶数条,就称为偶点。要想一笔画成,必须中间点均是偶点,也就是有来路必有另一条去路,奇点只可能在两端。因此任何图能一笔画成,奇点要么没有,要么在两端) 。
推断方法
当欧拉在1736年访问普鲁士的哥尼斯堡(现俄罗斯加里宁格勒)时,他发现当地的市民正从事一项非常有趣的消遣活动。哥尼斯堡城中有一条名叫Pregel的河流横经其中,这项有趣的消遣活动是在星期六作一次走过所有七座桥的散步,每座桥只能经过一次而且起点与终点必须是同一地点。
欧拉把每一块陆地考虑成一个点,连接两块陆地的桥以线表示。
后来推论出此种走法是不可能的。他的论点是这样的,除了起点以外,每一次当一个人由一座桥进入一块陆地(或点)时,他(或她)同时也由另一座桥离开此点。所以每行经一点时,计算两座桥(或线),从起点离开的线与最后回到始点的线亦计算两座桥,因此每一个陆地与其他陆地连接的桥数必为偶数。
存在问题
著名数学家欧拉的画像
著名数学家欧拉的画像
七桥所成之图形中,没有一点含有偶数条数,因此上述的任务无法完成。
欧拉的这个考虑非常重要,也非常巧妙,它正表明了数学家处理实际问题的独特之处——把一个实际问题抽象成合适的“数学模型”。这种研究方法就是“数学模型方法”。这并不需要运用多么深奥的理论,但想到这一点,却是解决难题的关键。
接下来,欧拉运用图中的一笔画定理为判断准则,很快地就判断出要一次不重复走遍哥尼斯堡的7座桥是不可能的。也就是说,多少年来,人们费脑费力寻找的那种不重复的路线,根本就不存在。一个曾难住了那么多人的问题,竟是这么一个出人意料的答案!