Browse Source

提交依靠红外测距传感器走迷宫的代码

corvin 4 years ago
parent
commit
1002c82254

+ 209 - 0
src/infrared_maze/CMakeLists.txt

@@ -0,0 +1,209 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(infrared_maze)
+
+## Compile as C++11, supported in ROS Kinetic and newer
+# add_compile_options(-std=c++11)
+
+## Find catkin macros and libraries
+## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
+## is used, also find other catkin packages
+find_package(catkin REQUIRED COMPONENTS
+  ros_arduino_msgs
+  roscpp
+  geometry_msgs
+  nav_msgs
+  tf
+  std_msgs
+)
+
+## System dependencies are found with CMake's conventions
+# find_package(Boost REQUIRED COMPONENTS system)
+
+
+## Uncomment this if the package has a setup.py. This macro ensures
+## modules and global scripts declared therein get installed
+## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
+# catkin_python_setup()
+
+################################################
+## Declare ROS messages, services and actions ##
+################################################
+
+## To declare and build messages, services or actions from within this
+## package, follow these steps:
+## * Let MSG_DEP_SET be the set of packages whose message types you use in
+##   your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
+## * In the file package.xml:
+##   * add a build_depend tag for "message_generation"
+##   * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
+##   * If MSG_DEP_SET isn't empty the following dependency has been pulled in
+##     but can be declared for certainty nonetheless:
+##     * add a exec_depend tag for "message_runtime"
+## * In this file (CMakeLists.txt):
+##   * add "message_generation" and every package in MSG_DEP_SET to
+##     find_package(catkin REQUIRED COMPONENTS ...)
+##   * add "message_runtime" and every package in MSG_DEP_SET to
+##     catkin_package(CATKIN_DEPENDS ...)
+##   * uncomment the add_*_files sections below as needed
+##     and list every .msg/.srv/.action file to be processed
+##   * uncomment the generate_messages entry below
+##   * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
+
+## Generate messages in the 'msg' folder
+# add_message_files(
+#   FILES
+#   Message1.msg
+#   Message2.msg
+# )
+
+## Generate services in the 'srv' folder
+# add_service_files(
+#   FILES
+#   Service1.srv
+#   Service2.srv
+# )
+
+## Generate actions in the 'action' folder
+# add_action_files(
+#   FILES
+#   Action1.action
+#   Action2.action
+# )
+
+## Generate added messages and services with any dependencies listed here
+# generate_messages(
+#   DEPENDENCIES
+#   ros_arduino_msgs
+# )
+
+################################################
+## Declare ROS dynamic reconfigure parameters ##
+################################################
+
+## To declare and build dynamic reconfigure parameters within this
+## package, follow these steps:
+## * In the file package.xml:
+##   * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
+## * In this file (CMakeLists.txt):
+##   * add "dynamic_reconfigure" to
+##     find_package(catkin REQUIRED COMPONENTS ...)
+##   * uncomment the "generate_dynamic_reconfigure_options" section below
+##     and list every .cfg file to be processed
+
+## Generate dynamic reconfigure parameters in the 'cfg' folder
+# generate_dynamic_reconfigure_options(
+#   cfg/DynReconf1.cfg
+#   cfg/DynReconf2.cfg
+# )
+
+###################################
+## catkin specific configuration ##
+###################################
+## The catkin_package macro generates cmake config files for your package
+## Declare things to be passed to dependent projects
+## INCLUDE_DIRS: uncomment this if your package contains header files
+## LIBRARIES: libraries you create in this project that dependent projects also need
+## CATKIN_DEPENDS: catkin_packages dependent projects also need
+## DEPENDS: system dependencies of this project that dependent projects also need
+catkin_package(
+#  INCLUDE_DIRS include
+#  LIBRARIES infrared_maze
+#  CATKIN_DEPENDS ros_arduino_msgs roscpp
+#  DEPENDS system_lib
+)
+
+###########
+## Build ##
+###########
+
+## Specify additional locations of header files
+## Your package locations should be listed before other locations
+include_directories(
+ include
+ ${catkin_INCLUDE_DIRS}
+)
+
+## Declare a C++ library
+# add_library(${PROJECT_NAME}
+#   src/${PROJECT_NAME}/infrared_maze.cpp
+# )
+
+## Add cmake target dependencies of the library
+## as an example, code may need to be generated before libraries
+## either from message generation or dynamic reconfigure
+# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+
+## Declare a C++ executable
+## With catkin_make all packages are built within a single CMake context
+## The recommended prefix ensures that target names across packages don't collide
+add_executable(${PROJECT_NAME}_node src/infrared_maze.cpp)
+
+## Rename C++ executable without prefix
+## The above recommended prefix causes long target names, the following renames the
+## target back to the shorter version for ease of user use
+## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
+# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
+
+## Add cmake target dependencies of the executable
+## same as for the library above
+add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+
+## Specify libraries to link a library or executable target against
+target_link_libraries(${PROJECT_NAME}_node
+   ${catkin_LIBRARIES}
+ )
+
+#############
+## Install ##
+#############
+
+# all install targets should use catkin DESTINATION variables
+# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
+
+## Mark executable scripts (Python etc.) for installation
+## in contrast to setup.py, you can choose the destination
+# install(PROGRAMS
+#   scripts/my_python_script
+#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+# )
+
+## Mark executables for installation
+## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
+# install(TARGETS ${PROJECT_NAME}_node
+#   RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+# )
+
+## Mark libraries for installation
+## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
+# install(TARGETS ${PROJECT_NAME}
+#   ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+#   LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+#   RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
+# )
+
+## Mark cpp header files for installation
+# install(DIRECTORY include/${PROJECT_NAME}/
+#   DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
+#   FILES_MATCHING PATTERN "*.h"
+#   PATTERN ".svn" EXCLUDE
+# )
+
+## Mark other files for installation (e.g. launch and bag files, etc.)
+# install(FILES
+#   # myfile1
+#   # myfile2
+#   DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
+# )
+
+#############
+## Testing ##
+#############
+
+## Add gtest based cpp test target and link libraries
+# catkin_add_gtest(${PROJECT_NAME}-test test/test_infrared_maze.cpp)
+# if(TARGET ${PROJECT_NAME}-test)
+#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
+# endif()
+
+## Add folders to be run by python nosetests
+# catkin_add_nosetests(test)

+ 19 - 0
src/infrared_maze/README.md

@@ -0,0 +1,19 @@
+# blackTornadoRobot红外走迷宫功能
+走迷宫功能包,可通过红外传感器数据使小车在迷宫中行进。
+
+在param.yaml文件中可调整一些走迷宫时用到的参数。
+
+小车走迷宫的主要逻辑为:将迷宫看作由50cmX50cm方格添加障碍墙之后组成的环境,小车每次行进皆为50cm即行走一格,转弯角度为90度。小车每行进一格后会获取当前红外传感器数据,优先左转,其次直行,最后右转。
+
+### 建图运行方法
+首先启动小车
+
+```sh
+$ roslaunch robot_bringup robot_bringup.launch
+```
+
+然后运行走迷宫程序
+```sh
+$ roslaunch infrared_maze infrared_maze.launch
+```
+

+ 33 - 0
src/infrared_maze/cfg/param.yaml

@@ -0,0 +1,33 @@
+#####################################################
+# Copyright: 2016-2020 www.corvin.cn ROS小课堂
+# Description:使用小车上三个红外测距传感器进行避障
+#   走迷宫,这里是一些可以配置的参数.
+#   infrared_topic:订阅的红外传感器发布数据的话题.
+#   cmd_topic:控制小车移动的话题名.
+#   yaw_service:发布IMU模块yaw偏行角的服务.
+#   infrared_service:发布红外测据信息的服务名.
+#   linear_x:移动时前进速度大小.
+#   angular_speed:原地转圈时角速度大小.
+#   warn_dist:小车是否可以前进的距离.
+#   tolerance_dist:距离容忍值.
+#   odom_frame:odom的tf名称.
+#   base_frame:底盘的tf名称.
+#   forward_dist:每次前进时移动的距离.
+# Author: corvin
+# History:
+#   20200404:init this file.
+#   20200406:增加yaw service,rate参数.
+#   20200412:增加获取红外测距信息的service.
+#   20200424:更新注释,增加参数介绍.
+######################################################
+infrared_topic: /mobilebase_arduino/sensor/GP2Y0A41
+cmd_topic: /cmd_vel
+yaw_service: /imu_node/GetYawData
+infrared_service: /mobilebase_arduino/getInfraredDistance
+odom_frame: /odom_combined
+base_frame: /base_footprint
+linear_x: 0.27
+angular_speed: 1.0
+warn_dist: 0.25
+tolerance_dist: 0.05
+forward_dist: 0.50

+ 16 - 0
src/infrared_maze/launch/infrared_maze.launch

@@ -0,0 +1,16 @@
+<!--
+  Copyright: 2016-2020 www.corvin.cn
+  Author: jally, corvin
+  Description:
+    maze with infrared
+  History:
+    20200325: intial this file.
+-->
+<launch>
+  <arg name="cfg_file" default="$(find infrared_maze)/cfg/param.yaml" />
+
+  <!-- startup infrared_obstacle_avoidance_node -->
+  <node pkg="infrared_maze" type="infrared_maze_node" name="infrared_maze_node" output="screen">
+    <rosparam file="$(arg cfg_file)" command="load" />
+  </node>
+</launch>

+ 67 - 0
src/infrared_maze/package.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<package format="2">
+  <name>infrared_maze</name>
+  <version>0.0.0</version>
+  <description>The infrared_maze package</description>
+
+  <!-- One maintainer tag required, multiple allowed, one person per tag -->
+  <!-- Example:  -->
+  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
+  <maintainer email="jally_zhang@corvin.cn">jally</maintainer>
+
+
+  <!-- One license tag required, multiple allowed, one license per tag -->
+  <!-- Commonly used license strings: -->
+  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
+  <license>TODO</license>
+
+
+  <!-- Url tags are optional, but multiple are allowed, one per tag -->
+  <!-- Optional attribute type can be: website, bugtracker, or repository -->
+  <!-- Example: -->
+  <!-- <url type="website">http://wiki.ros.org/infrared_maze</url> -->
+
+
+  <!-- Author tags are optional, multiple are allowed, one per tag -->
+  <!-- Authors do not have to be maintainers, but could be -->
+  <!-- Example: -->
+  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->
+
+
+  <!-- The *depend tags are used to specify dependencies -->
+  <!-- Dependencies can be catkin packages or system dependencies -->
+  <!-- Examples: -->
+  <!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
+  <!--   <depend>roscpp</depend> -->
+  <!--   Note that this is equivalent to the following: -->
+  <!--   <build_depend>roscpp</build_depend> -->
+  <!--   <exec_depend>roscpp</exec_depend> -->
+  <!-- Use build_depend for packages you need at compile time: -->
+  <!--   <build_depend>message_generation</build_depend> -->
+  <!-- Use build_export_depend for packages you need in order to build against this package: -->
+  <!--   <build_export_depend>message_generation</build_export_depend> -->
+  <!-- Use buildtool_depend for build tool packages: -->
+  <!--   <buildtool_depend>catkin</buildtool_depend> -->
+  <!-- Use exec_depend for packages you need at runtime: -->
+  <!--   <exec_depend>message_runtime</exec_depend> -->
+  <!-- Use test_depend for packages you need only for testing: -->
+  <!--   <test_depend>gtest</test_depend> -->
+  <!-- Use doc_depend for packages you need only for building documentation: -->
+  <!--   <doc_depend>doxygen</doc_depend> -->
+  <buildtool_depend>catkin</buildtool_depend>
+  <build_depend>ros_arduino_msgs</build_depend>
+  <build_depend>roscpp</build_depend>
+  <build_depend>tf</build_depend>
+  <build_export_depend>ros_arduino_msgs</build_export_depend>
+  <build_export_depend>roscpp</build_export_depend>
+  <exec_depend>ros_arduino_msgs</exec_depend>
+  <exec_depend>roscpp</exec_depend>
+  <exec_depend>tf</exec_depend>
+
+
+  <!-- The export tag contains other, unspecified, tags -->
+  <export>
+    <!-- Other tools can request additional information be placed here -->
+
+  </export>
+</package>

+ 419 - 0
src/infrared_maze/src/infrared_maze.cpp

@@ -0,0 +1,419 @@
+/***************************************************************
+ Copyright(C): 2016-2020 ROS小课堂 www.corvin.cn
+ Description:三轮小车进行红外避障走迷宫.根据前,左,右三个红外测距
+   信息来进行移动,这里的移动策略是每次移动0.5m,然后再判断距离.
+   移动时向左转优先,其次直行,最后是右转.
+ Author: jally, corvin
+ History:
+    20200404:增加可以直接转90度,掉头的功能 by corvin.
+    20200412:增加使用服务方式来获取红外测距值-corvin.
+    20200424:增加每次前进时移动距离的参数,可以配置.-corvin
+ **************************************************************/
+#include <ros/ros.h>
+#include <std_msgs/Float32.h>
+#include <nav_msgs/Odometry.h>
+#include <geometry_msgs/Twist.h>
+#include <tf/transform_listener.h>
+#include "rasp_imu_hat_6dof/GetYawData.h"
+#include "ros_arduino_msgs/InfraredSensors.h"
+#include "ros_arduino_msgs/GetInfraredDistance.h"
+
+
+#define  GO_FORWARD   0
+#define  TURN_LEFT    1
+#define  TURN_RIGHT   2
+#define  TURN_BACK    3
+#define  HORIZ_MOVE   4
+
+#define  ERROR       -1
+
+//global variable
+ros::Publisher twist_pub;
+ros::ServiceClient yawSrvClient;
+rasp_imu_hat_6dof::GetYawData yawSrv;
+
+//红外测距相关的服务
+ros::ServiceClient distSrvClient;
+ros_arduino_msgs::GetInfraredDistance distSrv;
+
+float warn_dist = 0.25;  //warn check distance
+float tolerance_dist = 0.05; //对警告距离的容忍值
+float forward_dist = 0.50; //每次前进移动时走的距离
+
+float front_dist;
+float left_dist;
+float right_dist;
+
+std::string odomFrame;
+std::string baseFrame;
+
+float linear_x_speed = 0.27;
+float angular_speed = 1.0;
+
+float start_yaw_data = 0.0;
+int turnFlag = ERROR;
+
+/*********************************************************
+ * Descripition: 发布控制移动的消息,这里对于平面移动的
+ *   机器人只需要控制linear_x和angular_z即可.
+ ********************************************************/
+void publishTwistCmd(float linear_x, float angular_z)
+{
+    geometry_msgs::Twist twist_msg;
+
+    twist_msg.linear.x = linear_x;
+    twist_msg.linear.y = 0.0;
+    twist_msg.linear.z = 0.0;
+
+    twist_msg.angular.x = 0.0;
+    twist_msg.angular.y = 0.0;
+    twist_msg.angular.z = angular_z;
+
+    twist_pub.publish(twist_msg);
+}
+
+/**********************************************************
+ * Description:调用IMU板发布出来的yaw信息,可以根据该数据
+ *   来修正转弯时不准确的问题.注意这里的yaw数据为弧度值.
+ *   注意往右旋转为负值,左旋转为正值.右手定则.
+ *   注意在ROS中IMU数据中yaw的范围,具体表示如下:
+ *                0  -0
+ *                -----
+ *              /      \
+ *         1.57|        | -1.57
+ *              \      /
+ *               ------
+ *             3.14 -3.14
+ **********************************************************/
+void yawUpdate(const float start_yaw)
+{
+    float target = 0.0;
+    float diff = 10.0;
+    float angular = 0.0;
+    float now_yaw = 0.0;
+
+    //开始计算修正后的目标角度
+    if((turnFlag == GO_FORWARD)||(turnFlag == HORIZ_MOVE))
+    {
+        target = start_yaw;
+    }
+    else if(turnFlag == TURN_LEFT)
+    {
+        target = start_yaw + M_PI/2.0;
+        if(target > M_PI)
+        {
+            target = target - M_PI*2.0;
+        }
+    }
+    else if(turnFlag == TURN_RIGHT)
+    {
+        target = start_yaw - M_PI/2.0;
+        if(target < -M_PI)
+        {
+            target = target + M_PI*2.0;
+        }
+    }
+    else //turn back
+    {
+        target = start_yaw + M_PI;
+        if(target > M_PI)
+        {
+            target = target - M_PI*2.0;
+        }
+    }
+
+    //开始不断的计算偏差,调整角度
+    while(fabs(diff) > 0.01)
+    {
+        yawSrvClient.call(yawSrv);
+        now_yaw = yawSrv.response.yaw;
+        ROS_INFO("Now Yaw data:%f, Target Yaw:%f", now_yaw, target);
+
+        diff = target - now_yaw;
+        if(diff > 0)
+        {
+            angular = angular_speed;
+        }
+        else
+        {
+            angular = -angular_speed;
+        }
+        ROS_WARN("Yaw diff:%f, angular:%f", diff, angular);
+        publishTwistCmd(0, angular);
+        ros::Duration(0.04).sleep();
+    }
+    publishTwistCmd(0, 0); //在修正角度结束后应该立刻停止小车转动
+    ROS_INFO("Correct Yaw diff over !");
+}
+
+/****************************************************
+ * Description:控制小车前进移动0.5m
+ ***************************************************/
+void goForward(const float check_dist)
+{
+    tf::TransformListener tf_Listener;
+    tf::StampedTransform tf_Transform;
+    float dist = 0.0; //每次前进移动的距离
+    float front_dist = 0.0;
+
+    try
+    {
+        tf_Listener.waitForTransform(odomFrame, baseFrame, ros::Time(0), ros::Duration(5.0));
+    }
+    catch(tf::TransformException &ex)
+    {
+        ROS_ERROR("tf_Listener.waitForTransform timeout error !");
+        ROS_ERROR("%s", ex.what());
+        ros::shutdown();
+    }
+
+    tf_Listener.lookupTransform(odomFrame, baseFrame, ros::Time(0), tf_Transform);
+    float x_start = tf_Transform.getOrigin().x();
+    float y_start = tf_Transform.getOrigin().y();
+
+    distSrvClient.call(distSrv); //通过服务调用来获取测距值
+    front_dist = distSrv.response.front_dist; //记录当前测距值,防止撞墙
+    ROS_INFO("Front dist:%f", front_dist);
+    while((dist<check_dist)&&(front_dist>tolerance_dist*4.0)&&(ros::ok()))
+    {
+        ROS_INFO("Go forward, dist:%f", dist);
+        publishTwistCmd(linear_x_speed, 0);
+        ros::Duration(0.10).sleep(); //100 ms
+
+        tf_Listener.lookupTransform(odomFrame, baseFrame, ros::Time(0),tf_Transform);
+        float x = tf_Transform.getOrigin().x();
+        float y = tf_Transform.getOrigin().y();
+        dist = sqrt(pow((x - x_start), 2) + pow((y - y_start), 2));
+
+        distSrvClient.call(distSrv); //通过服务调用来获取测距值
+        front_dist = distSrv.response.front_dist; //记录当前测距值,防止撞墙
+        ROS_INFO("Front dist:%f", front_dist);
+    }
+    publishTwistCmd(0, 0); //stop move
+    ROS_INFO("Go forward finish !!!");
+}
+
+/*************************************************************
+ * Description:控制小车左右转90度,或者掉头180度.这里实现小车
+ *   转弯功能是通过不断监听odom和base_link之间的tf转换完成的.
+ ************************************************************/
+int controlTurn(int flag)
+{
+    tf::TransformListener tf_Listener;
+    tf::StampedTransform tf_Transform;
+    float angular = 0.0;
+    float check_angle = 0.0;
+
+    switch(flag)
+    {
+        case TURN_LEFT: //向左转动90°
+            turnFlag = TURN_LEFT;
+            angular = angular_speed;
+            check_angle = M_PI/2.0;
+            break;
+
+        case TURN_RIGHT: //向右转动90°
+            turnFlag = TURN_RIGHT;
+            angular = -angular_speed;
+            check_angle = M_PI/2.0;
+            break;
+
+        case TURN_BACK: //小车原地掉头180度
+            turnFlag = TURN_BACK;
+            check_angle = M_PI;
+            angular = angular_speed;
+            break;
+
+        case GO_FORWARD: //小车直行50cm
+            goForward(forward_dist);
+            return 1;
+
+        default:
+            ROS_ERROR("Turn flag error !");
+            return -1;
+    }
+
+    try
+    {
+        tf_Listener.waitForTransform(odomFrame, baseFrame, ros::Time(0), ros::Duration(5.0));
+    }
+    catch(tf::TransformException &ex)
+    {
+        ROS_ERROR("tf_Listener.waitForTransform timeout error !");
+        ROS_ERROR("%s", ex.what());
+        ros::shutdown();
+
+        return -2;
+    }
+
+    //ROS_INFO("Check_angle:%f, angular_speed:%f",check_angle, angular);
+    tf_Listener.lookupTransform(odomFrame, baseFrame, ros::Time(0), tf_Transform);
+    float last_angle = fabs(tf::getYaw(tf_Transform.getRotation()));
+    float turn_angle = 0.0;
+    ROS_INFO("first_angle:%f", last_angle);
+    while((fabs(turn_angle) < check_angle)&&(ros::ok()))
+    {
+        publishTwistCmd(0, angular); //原地转弯,不需要linear_x,y的控制
+        ros::Duration(0.10).sleep(); //100 ms
+
+        try
+        {
+            tf_Listener.lookupTransform(odomFrame, baseFrame, ros::Time(0), tf_Transform);
+        }
+        catch(tf::TransformException &ex)
+        {
+            ROS_ERROR("%s", ex.what());
+            continue;
+        }
+        float rotation = fabs(tf::getYaw(tf_Transform.getRotation()));
+        float delta_angle = fabs(rotation - last_angle);
+
+        turn_angle += delta_angle;
+        last_angle = rotation;
+        ROS_INFO("Turn angle:%f", turn_angle);
+    }
+    publishTwistCmd(0, 0); //原地转弯完成后,需要立刻停止小车的旋转
+    ROS_INFO("Turning finish !!!");
+    ros::Duration(0.1).sleep(); //100 ms
+
+    return 0;
+}
+
+/**********************************************************
+ * Description:控制小车移动在过道中间,比较左右两边的距离后
+ *   然后进行水平左右移动.使小车保持在过道中间位置.
+ **********************************************************/
+void horizMoveMiddle(float tolerance)
+{
+    float diff = 0.0; //计算左右两边距离差
+    float begin_yaw = 0.0;
+    float now_left  = 0.0;
+    float now_right = 0.0;
+
+    turnFlag = HORIZ_MOVE;
+    yawSrvClient.call(yawSrv); //记录平移前的角度,作为标准进行修正
+    begin_yaw = yawSrv.response.yaw;
+
+    distSrvClient.call(distSrv);
+    now_left = distSrv.response.left_dist; //获取左边距离
+    ros::Duration(0.02).sleep();//在获取两次传感器值之间需要加延迟
+    distSrvClient.call(distSrv);
+    now_right = distSrv.response.right_dist;//获取右边距离
+
+    diff = now_left - now_right;
+    ROS_INFO("diff:%f,left:%f,right:%f", diff, now_left, now_right);
+    while((fabs(diff)>tolerance)&&(now_left!=(float)0.3)&&(now_right!=(float)0.3))
+    {
+        ros::Duration(0.1).sleep(); //delay 100ms
+        yawUpdate(begin_yaw); //用于修正转歪的角度
+
+        distSrvClient.call(distSrv);
+        now_left = distSrv.response.left_dist;
+        ros::Duration(0.02).sleep();//在获取两次传感器值之间需要加延迟
+        distSrvClient.call(distSrv);
+        now_right = distSrv.response.right_dist;
+
+        diff = now_left - now_right; //计算左右距离差值
+    }
+    //当平移结束后立刻停止移动
+    publishTwistCmd(0, 0); //stop move
+}
+
+/***************************************************************************
+ * Description:检查三个传感器数据,然后控制小车移动.这里需要防止小车在原地
+ *   进行连续两次旋转,在每次转弯后必须有个直行.这里需要注意的是当小车在转弯
+ *   后一定要有一个可以修正转弯角度的功能,否则转弯后角度不准确小车前进方向
+ *   会错.这里的走迷宫策略是左转优先,中间是直行,最后是右转.
+ *   当前方,左边,右边都无法移动时,进行掉头动作,然后直行.
+ **************************************************************************/
+void checkInfraredDist(float infrared_f,float infrared_l,float infrared_r,
+        float tolerance, float warn_distance)
+{
+    static int flag = 0; //记录是否转过弯的标志
+
+    yawSrvClient.call(yawSrv); //通过服务调用来获取yaw值
+    start_yaw_data = yawSrv.response.yaw; //记录当前yaw值,用于后面修正
+
+    //判断能否左转,并且上一次动作不能是转弯
+    if((infrared_l == (float)0.3)&&(flag != 1))
+    {
+        ROS_WARN("turn Left! yaw_data:%f", start_yaw_data);
+        turnFlag = TURN_LEFT;
+        flag = 1; //设置转弯标志
+    }
+    else if(infrared_f > warn_distance)//判断能否直行
+    {
+        //始终控制小车保持在过道的中间位置
+        ROS_WARN("go Forward ! yaw_data: %f", start_yaw_data);
+        horizMoveMiddle(tolerance);
+        turnFlag = GO_FORWARD;
+        flag = 0; //设置直行标志
+    }
+    else if((infrared_r == (float)0.3)&&(flag != 1))//判断能否右转
+    {
+        ROS_WARN("turn Right ! yaw_data: %f", start_yaw_data);
+        turnFlag = TURN_RIGHT;
+        flag = 1; //设置转弯标志
+    }
+    else //小车掉头
+    {
+        ROS_WARN("turn Back ! yaw_data: %f", start_yaw_data);
+        turnFlag = TURN_BACK;
+    }
+
+    controlTurn(turnFlag); //开始执行动作
+}
+
+/*****************************************************************************
+ * Description: 订阅红外测距传感器话题后的回调函数,根据三个传感器数据进行走
+ *   迷宫.
+ ****************************************************************************/
+void infrared_callback(const ros_arduino_msgs::InfraredSensors::ConstPtr& msg)
+{
+    ROS_INFO("front left right distance:[%f %f %f]", msg->front_dist,
+            msg->left_dist, msg->right_dist);
+    front_dist = msg->front_dist;
+    left_dist  = msg->left_dist;
+    right_dist = msg->right_dist;
+
+    //根据三个传感器反馈的测距值开始移动
+    checkInfraredDist(front_dist, left_dist, right_dist, tolerance_dist, warn_dist);
+    yawUpdate(start_yaw_data); //移动完成后开始更新yaw值
+}
+
+/************************************************************
+ * Description:主函数初始化节点,读取配置参数,订阅和发布话题,
+ *   在订阅的红外测距数据话题回调函数中进行移动,通过调用yaw
+ *   服务进行转弯角度的修正.
+ ************************************************************/
+int main(int argc, char **argv)
+{
+    std::string infrared_topic;
+    std::string cmd_topic;
+    std::string yaw_service;
+    std::string infrared_service;
+
+    ros::init(argc, argv, "infrared_maze_node");
+    ros::NodeHandle handle;
+
+    ros::param::get("~infrared_topic", infrared_topic);
+    ros::param::get("~cmd_topic", cmd_topic);
+    ros::param::get("~yaw_service", yaw_service);
+    ros::param::get("~infrared_service", infrared_service);
+    ros::param::get("~linear_x",  linear_x_speed);
+    ros::param::get("~angular_speed", angular_speed);
+    ros::param::get("~warn_dist", warn_dist);
+    ros::param::get("~tolerance_dist", tolerance_dist);
+    ros::param::get("~odom_frame", odomFrame);
+    ros::param::get("~base_frame", baseFrame);
+    ros::param::get("~forward_dist", forward_dist);
+
+    ros::Subscriber sub_infrared = handle.subscribe(infrared_topic, 1, infrared_callback);
+    twist_pub = handle.advertise<geometry_msgs::Twist>(cmd_topic, 1);
+    yawSrvClient = handle.serviceClient<rasp_imu_hat_6dof::GetYawData>(yaw_service);
+    distSrvClient = handle.serviceClient<ros_arduino_msgs::GetInfraredDistance>(infrared_service);
+
+    ros::spin();
+    return 0;
+}
+