ROS+P3DX代码注解 [ 1 ] -- RosAria_client代码注解

首先当拿到源码的时候,应该先从CMakeLists.txt看起来,然后在看对应的源码。

#cmake最小支持的版本
cmake_minimum_required(VERSION 2.8.3)
#项目的名称
project(rosaria_client)
#添加一些package的
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  geometry_msgs
  rosaria
)
catkin_package()
#包含的子目录
include_directories(
  ${catkin_INCLUDE_DIRS}
)
## Declare a cpp executable
#然后是添加子文件,前面的地方执行文件的名称,后面的是这个cpp的源文件
add_executable(go_three_second src/go_three_second.cpp)
add_executable(spin_counterclockwise src/spin_counterclockwise.cpp)
add_executable(spin_clockwise src/spin_clockwise.cpp)
add_executable(teleop src/teleop.cpp)
add_executable(print_state src/print_state.cpp)
add_executable(interface src/interface.cpp)
add_executable(enable_motors src/enable_motors.cpp)
#然后就是将每个Cpp文件分别连接库
target_link_libraries(go_three_second 
   ${catkin_LIBRARIES}
)

target_link_libraries(spin_counterclockwise 
   ${catkin_LIBRARIES}
)

target_link_libraries(spin_clockwise 
   ${catkin_LIBRARIES}
)

target_link_libraries(teleop 
   ${catkin_LIBRARIES}
)

target_link_libraries(print_state
  ${catkin_LIBRARIES}
)

target_link_libraries(interface
  ${catkin_LIBRARIES}
  )

target_link_libraries(enable_motors
  ${catkin_LIBRARIES}
  )

总结:
cmakelists.txt的总体的框架

#cmake最小支持的版本
cmake_minimum_required(VERSION 2.8.3)
#项目的名称
project(rosaria_client)
#添加一些package的
find_package(catkin REQUIRED COMPONENTS
  roscpp
)
catkin_package()
#包含的子目录
include_directories(
  ${catkin_INCLUDE_DIRS}
)
#然后是添加子文件,前面的地方执行文件的名称,后面的是这个cpp的源文件
#add_executable(执行文件的名称 从项目主要目录找到cpp)
add_executable(go_three_second src/go_three_second.cpp)
#然后就是将每个Cpp文件分别连接库
target_link_libraries(go_three_second 
   ${catkin_LIBRARIES}
)

enable_motors.cpp:

/*
作用:启动电机
*/
#include 
int main(int argc, char **argv)
{
//初始化
  ros::init(argc, argv, "enable_motors");

//实例化一个句柄
  ros::NodeHandle nh;

//std::system("")相当于在终端输入后面的指令
std::system("rosservice call /RosAria/enable_motors");

//对ros进行输入
  ROS_INFO_STREAM("Motors are enabled!");

  return 0;
}

spin_clockwise.cpp:

/*

作用:让车旋转45度后停下来(将角速度和线速度都变成0)
*/

#include
#include
int main(int argc, char **argv)
{
//初始化
  ros::init(argc, argv, "Spin_Clockwise");

//实例化句柄
  ros::NodeHandle nh;

/*
补充:
发布消息,在RosAria/cmd_vel这个话题上面发布消息,这里的1000就是一个尺度,意义不大(对与初学者而言)
发布的消息的数据类型是是genmetry_msgs/Twist
我们可以通过什么指令来查看发布的消息的数据类型
输入rostopic type 话题名称(例如:/RosAria/cmd_vel)就会返回geometry_msgs/Twist,当然我们一般
对cmd_vel的数据类型,都是吧他定义成geometry_msgs/Twist这个数据类型
接着,我们可以输入 rosmsg show geometry_msgs/Twist来显示
显示出来是三个浮点形,因此在后面是有三数字的,并且有2组是因为一个是线速度,一个角速度
同时,我们也可一在终端发布简单的命令,例如:
rostopic pub [话题] [数据类型] [参数例如:--'[2 0 0]' '[0 0 0]']
*/

//在句柄nh上发布话题
  ros::Publisher pub = nh.advertise("RosAria/cmd_vel", 1000);

//实例化一个geometry_msgs命名空间下的Twist对象,这个对象的名字就叫做msg
  geometry_msgs::Twist msg;

//设定参数,最开始的速度,运动的时间持续时间,角速度 PI 
  double BASE_SPEED = 0.2, MOVE_TIME = 3.0, CLOCK_SPEED = 0.5, PI = 3.14159;

//判断旋转的
  int count = 0;

//实例化ros命名空间下的Rate对象,对这个对象的进行初始化,将速度赋值进去
  ros::Rate rate(CLOCK_SPEED);

  // Make the robot stop (robot perhaps has a speed already) 
//为了防止意外,让车的初速度设置为0,这里的原始是根据现实出msg 的数据类型
  msg.linear.x = 0;
  msg.linear.y = 0;
  msg.linear.z = 0;
  msg.angular.x = 0;
  msg.angular.y = 0;
  msg.angular.z = 0;
  pub.publish(msg);


/*
ros::ok()这个函数用于当你按下ctrl+c的时候就会返回false,因此经常用于while,或者其他判断语句当中
或者当MOVE_TIME/CLOCK_SPEED +1 这个数值不大于0的时候,首先这里是想要旋转6次,然后count的自己+1就,
后面这个部分是一个定值,就是说7.那么就让count循环了6次。
*/
  while(ros::ok() && count1)
  {
      // Spin PI/4 
/*
修改msg.angular.z的数值,根据那个结构,然后发布这个消息,
这里的move_time/clock_speed 就是让那他每秒转pi/4的6分一。那么旋转6秒
这个旋转的框架还是和厉害的。
*/
      if (count == 0 || count == 1)
        {
           msg.angular.z = -1 * PI/ int(MOVE_TIME/CLOCK_SPEED) / 4;
           pub.publish(msg);
        }
      //向屏幕端输出下面的信息
      ROS_INFO_STREAM("The robot is now spinning clockwise!");

      //然后这里进行自加1
      count++;

     //调用ros命名空间下的spionOnce()函数,如果这个程序当中有订阅者,那么这条语句就必须存在,为什么在这里写,因为咋这里旋转啊
      ros::spinOnce();

      //休眠一下,默认是每个1HZ,也就是说1秒刷新一次。也就是说,程序到时候刷新几秒
      rate.sleep();
  }

    // Stop the spin停止旋转,并且将原来的线速度都变成0,并且将速度为0这个消息在发布到msg当中,这里为什么要用一个for语句循环两侧,我就不知道了
  for(int i = 0; i < 2; i++)
  {
      msg.angular.x = 0;
      msg.angular.y = 0;
      msg.angular.z = 0;
      pub.publish(msg);
  }

  //输出辅助信息  
  ROS_INFO_STREAM("The robot finished spinning 45 degrees!");

   // Guard, make sure the robot stops保证这个时候的线速度也是0,并且进行过发布
   rate.sleep();
   msg.linear.x = 0;
   msg.linear.y = 0;
   msg.linear.z = 0;
   pub.publish(msg);
}

teleop.cpp:

/*
功能:实现箭头控制,以及ctrl+c表示暂停
*/

#include 
#include 
#include 
#include 
#include 
/*
箭头和16进制的对应关系
*/
#define KEYCODE_R 0x43 //右
#define KEYCODE_L 0x44 //左
#define KEYCODE_U 0x41 //上
#define KEYCODE_D 0x42 //下
#define KEYCODE_Q 0x71 //停止
#define KEYCODE_SPACE 0x20 //空格


/*
TeleopRosAria的功能
*/
class TeleopRosAria
{
  public:
    TeleopRosAria();//函数功能:函数发布消息,并且给句柄赋值
    void keyLoop();
  private:
    ros::NodeHandle nh_;//
    double linear_, angular_, l_scale_, a_scale_;
    ros::Publisher twist_pub_;
};
TeleopRosAria::TeleopRosAria():
  linear_(0),
  angular_(0),
  l_scale_(2.0),
  a_scale_(2.0)
{

//这个param给scale_angular附上初始值
  nh_.param("scale_angular", a_scale_, a_scale_);
  nh_.param("scale_linear", l_scale_, l_scale_);

//发布一个话题,并且设置队列的长度是1
  twist_pub_ = nh_.advertise("RosAria/cmd_vel", 1);
}


//这是帧率
int kfd = 0;

//定义结构体
struct termios cooked, raw;

/*
补充:
这个函数包含在 termios.h头文件中
tcsetarr(int fd, int optional_action,const struct)函数用于设置终端参数
另外const * 在使用的时候,就是& 一一对应就好
参数列表: fd 是帧率 optional_action用于控制修改起作用的时间 strcut保存要修改的参数
option_action:
TCSANOW:不等待数据传输完毕就立即改变属性
*/
/*
暂停函数,全局函数
*/
void quit(int sig)
{
  tcsetattr(kfd, TCSANOW, &cooked);

  ros::shutdown();//如果按下ctrl+c立即退出
  exit(0);
}



//函数主线程的入口
int main(int argc, char** argv)
{

  ros::init(argc, argv, "teleop_RosAria");
  TeleopRosAria teleop_RosAria;

/*
补充:signal()函数在头文件 signal.h中,
signal(参数1,参数2)
参数1:我们要进行处理的信信号
参数2:我们要处理的方式
SIGINT是由于interrupt Key产生
quit是一个全局函数
*/

//设置某一个信号对应的动作,这里设置的应该是强制结束的动作。
  signal(SIGINT,quit);

//调用keyloop函数
  teleop_RosAria.keyLoop();
  return(0);
}




//功能:键盘控制

void TeleopRosAria::keyLoop()
{
  char c;
  bool dirty=false;
  // get the console in raw mode 得到控制的初始模型

/*
补充:tcgetattr函数在termios.h头文件中,用于获取终端的相关参数 kdf是一个全局变量
memcpy函数在string.h文件中,用于从src指定的位置拷贝N个字节到目标dest所指的内存地址的起始的位置
memcpy(src,dest,n) 
raw是一个结构体,表示:
结构体的c_flag表示本地模式标志说明:
ICANON说明是启动标准模式
ECHO应该受到一个ERASE控制符的时候删除前一个显示符号,我觉着这个地方是为了箭头做准备的保护机制。
*/
  tcgetattr(kfd, &cooked);
  memcpy(&raw, &cooked, sizeof(struct termios));
  raw.c_lflag &=~ (ICANON | ECHO);
  // Setting a new line, then end of file 在文件后面设置一个新的线程

/*
c_cc[VEOF]默认的控制符号 D,在标准模式下,使用read()返回0 ,标志一个文件结束
c_cc[VEOL]在行尾加上一个换行符号("\n")标志一个行的结束,重新开始一行
*/
  raw.c_cc[VEOL] = 1;
  raw.c_cc[VEOF] = 2;
  tcsetattr(kfd, TCSANOW, &raw);

//输出辅助信息
  puts("Reading from keyboard");
  puts("---------------------------");
  puts("Use arrow keys to move the robot.");
  puts("Press the space bar to stop the robot.");
  puts("Press q to stop the program");

//死循环
  for(;;)
  {
    // get the next event from the keyboard 从键盘得到下一个事件
    if(read(kfd, &c, 1) < 0)
      {
      perror("read():");//将上一个函数发生错误的原因输出到设备参数中
      exit(-1);
      }

//线速度的角度速度为0
    linear_=angular_=0;

//信息在程序中运行不直接显示到终端上
    ROS_DEBUG("value: 0x%02X\n", c);

//箭头控制
    switch(c)
      {
        case KEYCODE_L:
          ROS_DEBUG("LEFT");
          angular_ = 0.1;
          linear_ = 0;
          dirty = true;
          break;
        case KEYCODE_R:
          ROS_DEBUG("RIGHT");
          angular_ = -0.1;
          linear_ = 0;
          dirty = true;
          break;
        case KEYCODE_U:
          ROS_DEBUG("UP");
          linear_ = 0.1;
          angular_ = 0;
          dirty = true;
          break;
        case KEYCODE_D:
          ROS_DEBUG("DOWN");
          linear_ = -0.1;
          angular_ = 0;
          dirty = true;
          break;
        case KEYCODE_SPACE:
          ROS_DEBUG("STOP");
          linear_ = 0;
          angular_ = 0;
          dirty = true;
          break;
      case KEYCODE_Q:
        ROS_DEBUG("QUIT");
        ROS_INFO_STREAM("You quit the teleop successfully");
        return;
        break;
    }
    //实例化对象
    geometry_msgs::Twist twist;

    //这个里面angular里面肯定是有继承关系的
    twist.angular.z = a_scale_*angular_;
    twist.linear.x = l_scale_*linear_;

    //
    if(dirty ==true)
    {
    /*
    只是发布一次消息
    */
      twist_pub_.publish(twist);
      dirty=false;
    }
  }
  //return 相当与break吧
  return;
}

print_state.cpp:

/*
功能:输出先锋机器人状态的信息
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  // for std :: setprecision and std :: fixed

int battery_msg_count = 0, bumper_msg_count = 0;//初始化保险杠的距离和电池的状态
/*
补充:setprecision 控制输出流显示的浮点数的有效数字的个数(会有四舍五入) 需要加入头文件iomanip.h
std::fix表示用一般的方式输出浮点数

*/

/* checks pose messages and outputs them to user 
输出当前位置的和角度,用浮点数输出
*/
void poseMessageReceived(const nav_msgs::Odometry& msg) 
{
    std::cout << std::setprecision(2) << std::fixed << /* output the pose information using standard output */
      "Current position=(" << msg.pose.pose.position.x << ", " << msg.pose.pose.position.y << ") " << 
      "Current direction=" << std::setprecision(2) << std::fixed << msg.pose.pose.orientation.w<<"\r";

      std::flush(std::cout);
}




/* output the state of the bumpers using rosaria 
使出保险杠的状态
*/

void bumperStateMessageReceived(const rosaria::BumperState &msg)//这个地方是一个形参
{
    int front_size, rear_size; //定义前面的距离和后面的剧烈   
    if (bumper_msg_count == 0)
    {
//      ROS_INFO_STREAM("The front bumpers are "<
        front_size = sizeof(msg.front_bumpers) / sizeof(bool);
        rear_size = sizeof(msg.rear_bumpers) / sizeof(bool);
        ROS_INFO_STREAM("The front bumpers state are('1' means good): ");//输出辅助信息
      std::cout << "    ";

        for (int i=0;iif (msg.front_bumpers[i])
            std::cout<<'1';
      else
        std::cout<<'0';
//换行
        std::cout<<std::endl;
        ROS_INFO_STREAM("The rear bumpers state are('1' means good): ");
      std::cout << "    ";
        for (int i=0;iif (msg.rear_bumpers[i])
        std::cout<<'1';
      else
        std::cout<<'0';
        std::cout<<std::endl;
        bumper_msg_count++;
    }
}

/* check the status of the battery charge 检查电池的状态 分别对应msg的类型,然后输出就可以啦*/
void batteryStateOfChargeMessageReceived(const std_msgs::Float32 msg)
{
    // Right now this feature is not included in the pioneer-3 robot    
    ROS_INFO_STREAM("The battery state of charge is "</* check + output the voltage of the battery using standard output 检查电压的状态 */
void batteryVoltageMessageReceived(const std_msgs::Float64 msg)
{  
    if (battery_msg_count == 0)
    {
      battery_msg_count++;
      ROS_INFO_STREAM("The battery voltage is "<< msg);
    }
}

void batteryChargeStateMessageReceived(const std_msgs::Int8 msg)
{
    // Right now this feature is not included in the pioneer-3 robot
    ROS_INFO_STREAM("The battery charge state message received is "<< msg);
}

/* check the state of the motor and output using standard output 检查发动机的状态*/
void motorsStateMessageReceived(const std_msgs::Bool msg)
{
    if (msg.data)
        ROS_INFO_STREAM("The motor is good");
    else
        ROS_INFO_STREAM("The motor is bad");
}

/* call all of the functions implemented above and provide user with robot state info */
int main(int argc, char **argv)
{
    // Initialize the ROS system and become a node.初始化
    ros::init(argc, argv, "print_aria_state"); ros::NodeHandle nh;
    // Create a subscriber object .
    //就爱嗯这个订阅各自的话题
    ros::Subscriber pose, bumper_state, battery_state_of_charge, battery_voltage, battery_charge_state, motors_state;
    pose = nh.subscribe("RosAria/pose", 1000, &poseMessageReceived) ; //supply pose
    bumper_state = nh.subscribe("RosAria/bumper_state", 1000, &bumperStateMessageReceived) ; //inform bumper state
    battery_state_of_charge = nh.subscribe("RosAria/bumper_state_of_charge", 1000, &batteryStateOfChargeMessageReceived) ; //inform state of charge
    battery_voltage = nh.subscribe("RosAria/battery_voltage", 1000, &batteryVoltageMessageReceived) ; //inform battery voltage level
    battery_charge_state = nh.subscribe("RosAria/battery_charge_state", 1000, &batteryChargeStateMessageReceived) ; //inform charge state
    motors_state = nh.subscribe("RosAria/motors_state", 1000, &motorsStateMessageReceived) ; //inform motor state
    // Let ROS take over.悬停 
    ros::spin(); 
}

RosAria_client.launch文件


    "rosaria" type = "RosAria" name = "RosAria">
        "port" value="/dev/ttyUSB0" type="string"/>
    

    "rosaria_client" type="interface" name="RosAria_interface" output="screen"/>

在launch文件中添加节点和节点名称,以及对一些参数的修改

你可能感兴趣的:(【ROS探索】,先锋机器人ROS探索)