ros学习记录

在学习古月居ros21讲过程中的笔记,留做记录

linux系统基础操作

pwd 查看当前目录
cd XXX    进入下级目录
cd .. 返回上级目录
ls 查看目录下的所有文件
mkdir xxx  创建文件夹
touch xxx  创建文件
mv xxx /xxx/xxx/xxx   移动文件
cp xxx xxx/重命名    复制文件,并重命名
rm xxxx      删除文件
rm -r 删除文件夹
sudo apt update      sudo提升权限

rm --help  查看使用帮助


----------------------------------------------------------------------  


ros中的节点通信方式


1  话题通信  ---异步通信
数据从发布者到订阅者,单向

2  服务通信 ---同步通信
数据在客户端和服务端双向,请求/应答模式

----------------------------------------------------------------------  

启动小海龟


roscore     ----启动ros master  节点管理器
            rosrun  --启动ros功能包的某个节点
rosrun turtlesim turtlesim_node   启动海龟仿真器
rosrun turtlesim turtle_teleop_key  启动海龟控制器

----------------------------------------------------------------------  

ros命令行工具

rosnode list
rosnode info

rqt_graph    ---基于qt的可视化工具,展示节点图

rostopic list
rostopic pub 话题名 数据结构“具体内容”  ---向话题通道发布数据
rostopic pub -r 10 话题名 数据结构“具体内容”  ---向话题通道发布数据   以十hz频率发布,一秒发布十次

rosservice list   查看服务
rosservice call 服务名          ---调用服务
rosservice call /spwan  tap补全  ----产生新的海龟

rosbag     ---记录话题数据
rosbag record -a -O 压缩包名    -a  记录全部数据,-O打包成压缩包,保存在当前终端默认路径
rosbag play 文件名.bag    复现刚才的数据指令
----------------------------------------------------------------------  

创建工作空间(src build devel install),创建功能包

mkdir 工作空间名/src     ---创建工作空间
cd src
catkin_init_cworkspace    ---初始化,把文件夹变为ros工作空间
cd ..
catkin_make              ---编译工作空间
创建功能包(工作空间src目录下)
catkin_create_pkg 功能包名  依赖(如roscpp,rospy,std_msgs)   ---创建功能包
cd ..                     ---返回工作空间
source devel/setup.bash   ---设置环境变量
echo $ROS_PACKAGE_PATH    ---检查环境变量


----------------------------------------------------------------------  


通过程序控制海龟移动(发布者的编程实现)


创建工作空间
创建功能包:


catkin_create_pkg learning_topic roscpp rospy std_msgs geometry_msgs turtlesim
创建c++文件,编写代码:创建发布者代码
----------------------------------------------------------------------  


//创建一个发布者,将消息(geometry_msgs::Twist)发给指定话题(/turtle1/cmd_vel)

#include "ros/ros.h"
#include "geometry_msgs/Twist.h"

int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"publisher");     //“publisher”   节点名
  //创建节点句柄
  ros::NodeHandle n;                     //调用api,管理资源
  //创建一个publisher对象,发布话题名为turtle1/cmd_vel,消息类型为geometry_msgs::Twist,队列长度10
  ros::Publisher turtle_vel_pub=n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);
  //设置循环频率
  ros::Rate loop_rate(10);
  //发布消息
  while(ros::ok()){
  //初始化geometry_msgs::Twist类型的消息   封装数据
  geometry_msgs::Twist vel_mgs;
  vel_mgs.linear.x=1.0;
  vel_mgs.angular.z=1.0;
  //通过publisher发布消息
  turtle_vel_pub.publish(vel_mgs);
  ROS_INFO("Publisher[%0.2f m/s,%0.2f rad/s]",vel_mgs.linear.x,vel_mgs.angular.z);
  //按循环频率延时
  loop_rate.sleep();
 

  }
  return 0;
}

----------------------------------------------------------------------  


配置编译规则:编辑cmakelists文件


add_executable(publisher src/publisher.cpp)   ---设置要编译的文件和生成的可执行文件
               可执行文件名    编译文件名
               
target_link_libraries(publisher ${catkin_LIBRARIES})  ---把可执行文件与ros相关库做链接

编译运行


catkin_make    ---在工作空间中编译
source devel/setup.bash   ---配置环境变量(在工作空间中配置)(每次运行前都要配置一次,且旨在当前终端生效

---------------------------------------------------------------------- 

配置环境变量永久生效方法:

按ctrl+H 键显示主目录下的隐藏文件

在.bashrc文件中加上环境变量:source /home/user_name/workspace_name/devel/setup.bash

----------------------------------------------------------------------
roscore
rosrun turtlesim turtlesim_node
rosrun learning_topic publisher   ---运行功能包的程序   功能包名  节点名(也就是编译后的可执行文件名)
----------------------------------------------------------------------  


订阅海龟的位置信息(订阅者的编程实现)           ---可以和发布者放在同一功能包


//创建一个订阅者,从指定话题(/turtle1/pose)订阅消息(turtlesim::Pose)


----------------------------------------------------------------------
#include "ros/ros.h"
#include "turtlesim/Pose.h"

//创建回调函数,处理消息    回调函数处理时间不应过长
void poseCallback(const turtlesim::Pose::ConstPtr& mgs ){
  //将接受到的消息打印出来
  ROS_INFO("turtle_pose: x:%0.6f,y:%0.6f",mgs->x,mgs->y);
}

int main(int argc,char **argv){
   //ros节点初始化
  ros::init(argc,argv,"subscriber");     //"subscriber"   节点名
  //创建节点句柄
  ros::NodeHandle n;  
  //创建subscriber对象,订阅话题为/turtle1/pose,注册回调函数poseCallback
  ros::Subscriber pose_subscriber=n.subscribe("/turtle1/pose",10,poseCallback);
  //循环等待回调函数    不断查看队列有没有消息进来,有的话调用回调函数处理
  ros::spin();
 
  return 0;

}
----------------------------------------------------------------------


话题消息的定义与使用(完成个人信息的传输)


创建msg文件(在功能包里创建)


cd learning_topic       
mkdir msg                    ---必须是msg
touch Person.msg

msg文件内容:
string name   ---名字
uint8 age
uint8 sex

uint8 unknow=0
uint8 male=1
uint8 female=2

添加功能包依赖 在pacakge.xml


 <build_depend>message_generation</build_depend>    ---编译依赖,添加的是动态产生message的功能包
 <exec_depend>message_runtime</exec_depend>               ---运行依赖
 


添加编译选项 在cmakelists.txt


find_package(.......   message_generation)      ---在find_package中加上添加的功能包

  添加编译msg文件的配置项
add_message_files(FILES Person.msg)           
 ---加上编译的msg文件
generate_messages(DEPENDENCIES std_msgs )      
---编译msg文件时需要的库

catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime)
 ---添加运行时依赖

完成配置后在工作空间中编译
创建发布者,订阅者传输自定义消息
----------------------------------------------------------------------  


//创建一个发布者,发布话题/person_info,消息类型learning_topic::Person

#include "ros/ros.h"
#include "learning_topic/Person.h"

int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"person_publisher");     //“person_publisher”   节点名
  //创建节点句柄
  ros::NodeHandle n;                     //调用api,管理资源
  //创建一个publisher对象
  ros::Publisher person_pub=n.advertise<learning_topic::Person>("/person_info",10);
  //设置循环频率
  ros::Rate loop_rate(10);
  //发布消息
  while(ros::ok()){
  //初始化/person_info类型的消息   封装数据
  learning_topic::Person person_msg;
  person_msg.name="Tom";
  person_msg.age=18;
  person_msg.sex=learning_topic::Person::male;

  //通过publisher发布消息
  person_pub.publish(person_msg);
  ROS_INFO("person_msg[name:%s,age:%d,sex:
  %d]",person_msg.name.c_str(),person_msg.age,person_msg.sex);
  //按循环频率延时
  loop_rate.sleep();
 

  }
  return 0;
}

----------------------------------------------------------------------  


//创建一个订阅者,订阅话题/person_info,消息类型learning_topic::Person


#include "ros/ros.h"
#include "learning_topic/Person.h"

//创建回调函数,处理消息    回调函数处理时间不应过长
void personCallback(const learning_topic::Person::ConstPtr& msg ){
  //将接受到的消息打印出来
  ROS_INFO("person_msg: name:%s,age:%d,sex:%d",msg->name.c_str(),msg->age,msg->sex);
}

int main(int argc,char **argv){
   //ros节点初始化
  ros::init(argc,argv,"person_subscriber");     //"subscriber"   节点名
  //创建节点句柄
  ros::NodeHandle n;  
  //创建subscriber对象,订阅话题为/person_info,注册回调函数personCallback
  ros::Subscriber person_subscriber=n.subscribe("/person_info",10,personCallback);
  //循环等待回调函数    不断查看队列有没有消息进来,有的话调用回调函数处理
  ros::spin();
 
  return 0;

}
----------------------------------------------------------------------


配置编译规则(注意多了一条)


add_executable(person_publisher src/person_publisher.cpp)
target_link_libraries(person_publisher ${catkin_LIBRARIES})

add_dependencies(person_publisher ${PROJECT_NAME}_generate_messages_cpp)  
 ---将可执行文件与动态生成的消息产生依赖关系

add_executable(person_subscriber src/person_subscriber.cpp)
target_link_libraries(person_subscriber ${catkin_LIBRARIES})
add_dependencies(person_subscriber ${PROJECT_NAME}_generate_messages_cpp)

编译运行
----------------------------------------------------------------------

----------------------------------------------------------------------


通过编程创建一个新的海龟(客户端的编程实现)

创建功能包
catkin_create_pkg learning_service roscpp rospy std_msgs geometry_msgs turtlesim

创建客户端代码
//创建一个客户端对象,请求服务为/spawn,服务数据类型为turtlesim::Spawn

#include "ros/ros.h"
#include "turtlesim/Spawn.h"
int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"turtle_spawn");
  //创建ros节点句柄
  ros::NodeHandle node;
  //查询/spawn服务,创建client对象,请求服务为/spawn,服务数据类型为turtlesim::Spawn
  ros::service::waitForService("/spawn");    //查看是否有/spawn服务,有的话进行下一步,没有一直等待
  ros::ServiceClient add_turtle=node.serviceClient<turtlesim::Spawn>("/spawn");//创建客户端对象
 
  //初始化turtlesim::Spawn的请求数据
  turtlesim::Spawn srv;
  srv.request.x=2.0;
  srv.request.y=2.0;
  srv.request.name="turtle2";  //设置海龟的位置,名字
  //请求服务调用
  ROS_INFO("call service to turtlesim[x:%0.6f,y:%0.6f,name:%s]",srv.request.x,srv.request.y,srv.request.name.c_str());    //打印发送请求数据
  add_turtle.call(srv);    //通过call发送请求,然后等待,等待服务器的反馈数据后才继续下一步
  //显示服务调用结果
  ROS_INFO("spawn service successfully[name:%s]",srv.response.name.c_str());
  return 0;

}
----------------------------------------------------------------------


服务端编程实现

(创建一个服务端控制海龟运动,需创建客户端及发布者,客户端发送请求,服务端接受后通过话题通信完成请求,给客户端反馈)
//创建服务端,提供/command_turtle服务(自己定义的服务),服务数据类型std_srvs/Trigger

#include "ros/ros.h"
#include "geometry_msgs/Twist.h"   //海龟速度数据类型相关的头文件
#include "std_srvs/Trigger.h"      //服务数据类型相关的头文件

/*查看Trigger数据类型定义可以通过命令行指令-
rossrv show std_srvs/Trigger
运行结果:
---
bool success
string message

"---"之上是请求数据的定义,"---"之下是回复数据的定义*/

ros::Publisher turtle_vel_pub;  //创建一个全局发布者,方便回调函数调用
bool pubcommand=false;          //标志位,标志海龟是运动还是停止,默认停止false;

//service回调函数,输入请求参数req,输出回复参数res,  对接受数据进行处理
bool commandcallback(std_srvs::Trigger::Request &req,
                     std_srvs::Trigger::Response &res){
  pubcommand=!pubcommand;  //接受请求后为true,海龟运动,再次接受请求后,为false,海龟停止
  //显示请求数据
  ROS_INFO("publish turtle velocity command[%s]",pubcommand==true?"yes":"no");
  //设置反馈数据(由trigger定义)
  res.success=true;
  res.message="change turtle command state";
 
  return true;                  
}

int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"turtle_spawn");
  //创建ros节点句柄
  ros::NodeHandle n;
 
  //创建server对象,服务为/command_turtle,注册回调函数commandcallback
  ros::ServiceServer command_service=n.advertiseService("/command_turtle",commandcallback);
 
  //创建publisher对象,发布话题turtle1/cmd_vel,消息类型为geometry_msgs::Twist
  turtle_vel_pub=n.advertise<geometry_msgs::Twist>("turtle1/cmd_vel",10);
  //循环等待回调函数
  ROS_INFO("ready to receive turtle command");  //显示一下日志信息
  //设置循环发布频率
  ros::Rate loop_rate(10);
 
  while(ros::ok()){
  //查看回调函数队列,是否有消息进来,有的话调用回调函数,处理数据
  ros::spinOnce();
  //如果标志为ture,发布海龟速度指令
  if(pubcommand){
  //初始化数据
  geometry_msgs::Twist vel_msg;
  vel_msg.linear.x=0.5;
  vel_msg.angular.z=0.2;
  //发布数据
  turtle_vel_pub.publish(vel_msg);
  }
  //按循环频率延时,发布一次后隔一定时间再发布
  loop_rate.sleep();
  }
 
  return 0;
}
----------------------------------------------------------------------
发送请求
rosservice call /command_tuetle

----------------------------------------------------------------------


服务数据的定义与使用

创建srv文件(在功能包里创建)


cd learning_service
mkdir srv
touch Person.srv

srv文件内容:


string name
uint8 age
uint8 sex

uint8 unknown=0
uint8 male=1
uint8 female=2
---
string result

添加功能包依赖 在pacakge.xml(和话题消息定义相同)


 <build_depend>message_generation</build_depend>    ---编译依赖,添加的是动态产生message的功能包
 <exec_depend>message_runtime</exec_depend>               ---运行依赖
 


添加编译选项 在cmakelists.txt


find_package(.......   message_generation)      ---在find_package中加上添加的功能包

  添加编译srv文件的配置项
add_service_files(FILES Person.srv)        ---注意是add_service_files,不是                add_message_files      
 ---加上编译的msg文件
generate_messages(DEPENDENCIES std_msgs )      
---编译msg文件时需要的库

catkin_package(CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim message_runtime)
 ---添加运行时依赖

在工作空间编译生成对应头文件
----------------------------------------------------------------------

创建客户端代码


//创建一个客户端对象,请求服务为/show_person(自定义的),服务数据类型为learning_service::Person

#include "ros/ros.h"
#include "learning_service/Person.h"
int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"person_client");
  //创建ros节点句柄
  ros::NodeHandle node;
  //查询/show_person服务,创建client对象,请求服务为/show_person,服务数据类型为learning_service::Person
  ros::service::waitForService("/show_person");    //查看是否有/spawn服务,有的话进行下一步,没有一直等待
  ros::ServiceClient person_client=node.serviceClient<learning_service::Person>("/show_person");//创建客户端对象
 
  //初始化learning_service::Person的请求数据
  learning_service::Person srv;
  srv.request.name="name";
  srv.request.age=20;
  srv.request.sex=learning_service::Person::Request::male;  
  //请求服务调用
  ROS_INFO("call service to person_service[name:%s,age:%d,sex:%d]",srv.request.name.c_str(),srv.request.age,srv.request.sex);    //打印发送请求数据
  person_client.call(srv);    //通过call发送请求,然后等待,等待服务器的反馈数据后才继续下一步
  //显示服务调用结果
  ROS_INFO("show_person service successfully[result:%s]",srv.response.result.c_str());
  return 0;

}
----------------------------------------------------------------------

创建服务端代码


//创建服务端,提供/show_person服务(自己定义的服务),服务数据类型learning_service::Person

#include "ros/ros.h"
#include "learning_service/Person.h"      //服务数据类型相关的头文件
//service回调函数,输入请求参数req,输出回复参数res,  对接受数据进行处理
bool personcallback(learning_service::Person::Request &req,
                    learning_service::Person::Response &res){
                     
  ROS_INFO("person name[%s],age[%d],sex[%d]",req.name.c_str(),req.age,req.sex);
  //设置反馈数据
  res.result="Ok";
  return true;                  
}

int main(int argc,char **argv){
  //ros节点初始化
  ros::init(argc,argv,"person_server");
  //创建ros节点句柄
  ros::NodeHandle n;
  //创建server对象,服务为/show_person,注册回调函数personcallback
  ros::ServiceServer person_service=n.advertiseService("/show_person",personcallback);
  //循环等待回调函数
  ROS_INFO("ready to receive person information ");  //显示一下日志信息
  ros::spin();

  return 0;
}

----------------------------------------------------------------------

----------------------------------------------------------------------


配置编译规则(注意多了一条)


add_executable(person_client src/person_client.cpp)
target_link_libraries(person_client ${catkin_LIBRARIES})

add_dependencies(person_client ${PROJECT_NAME}_gencpp)  
 ---将可执行文件与动态生成的消息产生依赖关系

add_executable(person_server src/person_server.cpp)
target_link_libraries(person_server ${catkin_LIBRARIES})
add_dependencies(person_server ${PROJECT_NAME}_gencpp)

编译运行
----------------------------------------------------------------------

参数的使用与编程方法


ROS Master中存在一个参数服务器(parameter server),也就是全局变量字典,存着各个节点的参数,以字典的形式;各个节点都可以访问这些参数

参数命令行的使用


rosparam
rosparam list    ---显示当前所有参数
rosparam get param_key   ---获取某个参数的值
rosparam set param_key param_value  ---修改某个参数的值
修改参数后,节点的参数要发送请求后才会更新
rosservice call /clear "{}"     ---更新参数

rosparam dump file_name.yaml    ---保存参数到文件
rosparam load file_name.yaml    ---读取文件参数
rosparam delete param_key      ---删除某个参数

----------------------------------------------------------------------

通过程序使用参数


catkin_create_pkg learning_parameter roscpp rospy std_srvs   ---创建功能包

//编写程序,读取/设置海龟例程中的参数

#include "string"
#include "ros/ros.h"
#include "std_srvs/Empty.h"     /clear服务对应的数据类型
int main(int argc,char **argv){
  int red,green,blue;   //存储读取的参数
  //ros节点初始化
  ros::init(argc,argv,"parameter_config");
  //创建ros节点句柄
  ros::NodeHandle node;
 
  //读取背景颜色参数
  ros::param::get("/turtlesim/background_r",red);
  ros::param::get("/turtlesim/background_g",green);
  ros::param::get("/turtlesim/background_b",blue);
  ROS_INFO("get backgroud parameter: red:%d,green:%d,blue:%d",red,green,blue);
  //设置背景颜色参数
  ros::param::set("/turtlesim/background_r",255);
  ros::param::set("/turtlesim/background_g",255);
  ros::param::set("/turtlesim/background_b",255);
  ROS_INFO("set backgroud parameter:red:255,green:255,blue:255");
  //重新读取背景颜色参数
  ros::param::get("/turtlesim/background_r",red);
  ros::param::get("/turtlesim/background_g",green);
  ros::param::get("/turtlesim/background_b",blue);
  ROS_INFO("re-get backgroud parameter: red:%d,green:%d,blue:%d",red,green,blue);
  //调用服务,更新节点背景参数
  ros::service::waitForService("/clear");
  ros::ServiceClient clear_backgroud=node.serviceClient<std_srvs::Empty>("/clear");
  std_srvs::Empty srv;
  clear_backgroud.call(srv);
 
  sleep(1);
  return 0;

}
----------------------------------------------------------------------

ros中tf(transform 坐标变换)功能包


tf如何实现:广播和监听机制
sudo apt install ros-noetic-turtle-tf    ---安装turtle-tf功能包
roslaunch turtle_tf turtle_tf_demo.launch   ---启动launch文件(启动多个节点的脚本)
rosrun tf view_frames         ---可视化工具,可以看到所有tf之间的关系
rosrun tf tf_echo turtle1 turtle2    ---查询任意两个坐标系之间的关系
rosrun rviz rviz -d `rospack find turtle_tf`/rviz/turtle_rviz.rviz  ---启动rviz,3维可视化工具
----------------------------------------------------------------------

tf广播与监听的编程实现


catkin_create_pkg learning_tf roscpp rospy tf turtlesim   ---创建功能包

//创建tf广播器,产生tf数据,数据类型tf::Transform

#include "ros/ros.h"
#include "tf/transform_broadcaster.h"
#include "turtlesim/Pose.h"
 
std::string turtle_name;

 //传入参数是海龟的位置,x,y,z,theta
void posecallback(const turtlesim::PoseConstPtr& msg){
  //创建tf广播器
  static tf::TransformBroadcaster br;
 //初始化tf数据,也就是获取海龟与世界坐标系的坐标变换,包括平移和旋转参数
 tf::Transform transform;
 transform.setOrigin(tf::Vector3(msg->x,msg->y,0.0));   //设置平移参数  
 tf::Quaternion q;        //通过四元数的到旋转信息
 q.setRPY(0,0,msg->theta);    //通过饶x,y,z轴的旋转得到
 transform.setRotation(q);    ///设置旋转信息
 //这样就得到了海龟与世界坐标系的变换矩阵
 
 //广播world与海龟之间的tf数据                   广播当前时间     world和海龟之间的关系
 br.sendTransform(tf::StampedTransform(Transform,ros::Time::now(),"world",turtle_name));
}

int main(int argc,char** argv){
  //初始化ros节点
  ros::init(argc,argv,"turtle_tf_broadcaster");
  //判断输入参数,是turtle1,还是turtle2,如果不是的话报错
  if(argc!=2){
  ROS_ERROR("need turtle name as argument");
  return -1;
  }
  //注意,这个程序会执行两遍,分别计算turtle1和turtle2的坐标变化,但节点名相同会冲突,因此后面运行时要进行重映射
  turtle_name=argv[1];    //获取海龟名
  //订阅海龟的位姿话题
  ros::NodeHandle n;
  ros::Subscriber sub=n.subscribe(turtle_name+"/pose",10,&posecallback);
  //循环等待回调函数
  ros::spin();
  return 0;
}
----------------------------------------------------------------------

//创建tf监听器,获取任意两个坐标系之间的坐标变换关系;发布两个坐标系间的速度指令


#include "ros/ros.h"
#include "tf/transform_listener.h"
#include "geometry_msgs/Twist.h"     //速度相关的头文件
#include "turtlesim/Spawn.h"           //产生海龟的头文件

int main(int argc, char** argv){
    //初始化ros节点
  ros::init(argc,argv,"turtle_tf_listener");
  //创建节点句柄
  ros::NodeHandle n;
 
  //请求服务,产生第二只海龟
  ros::service::waitForService("/spawn");
  ros::ServiceClient add_turtle=n.serviceClient<turtlesim::Spawn>("/spawn");
  turtlesim::Spawn srv;    //取默认值
  add_turtle.call(srv);
 
  //创建发布turtle2速度指令的发布者
  ros::Publisher turtle2_vel=n.advertise<geometry_msgs::Twist>("/turtle2/cmd_vel",10);
 
  //创建tf监听器
  tf::TransformListener listener;
  ros::Rate rate(10.0);    //设置循环频率
  while(n.ok()){
  //获取turtle1和turtle2坐标系之间的tf数据
  tf::StampedTransform transform;
  try{
  //监听两个坐标系之间的关系
  //等待是否有这两个坐标系,有的话进行下一步        当前时刻      等待时间为3s,超时会抛出异常
  listener.waitForTransform("/turtle2","/turtle1",ros::Time(0),ros::Duration(3.0));
  //查询当前两个坐标系之间的关系,结果保存在transform
  listener.lookupTransform("/turtle2","/turtle1",ros::Time(0),transform);
  }
  catch(tf::TransformException &ex){
  ROS_ERROR("%s",ex.what());
  ros::Duration(1.0).sleep();
  continue;
  }
  //根据turtle1和turtle2坐标系之间的位置关系,发布turtle2的速度控制指令(位置关系会不断更新)
  geometry_msgs::Twist vel_msg;
  vel_msg.linear.x=0.5*sqrt(pow(transform.getOrigin().x(),2)+pow(transform.getOrigin().y(),2));       //根据位置矢量得到距离,控制速度
  vel_msg.angular.z=4.0*atan2(transform.getOrigin().y(),transform.getOrigin().x());
  //atan2(),求y/x的反正切,得到角度,根据角度控制角速度来控制转向
  turtle2_vel.publish(vel_msg);   //发布速度指令
 
  rate.sleep();
 }

 return 0;
}

----------------------------------------------------------------------

运行

roscore
rosrun turtlesim tortlesim_node
//运行广播器两次,广播turtle1和turtle2                           广播器中主函数接受的参数,海龟名
rosrun learning_tf turtle_tf_broadcaster __name:=turtle1_tf_broadcaster /turtle1
rosrun learning_tf turtle_tf_broadcaster __name:=turtle2_tf_broadcaster /turtle2
//__name:=turtle1_tf_broadcaster   这一部分是节点名重映射,将节点名turtle_tf_broadcaster重映射为turtle1_tf_broadcaster,使同样的程序运行后节点名不一样
rosrun learning_tf turtle_tf_listener
rosrun turtlesim turtle_teleop_key

----------------------------------------------------------------------

launch文件(启动多个节点的脚本,会自动启动rosmaster,用XML标记语言写)使用方法

launch文件语法


所有标签都要放到根标签<launch>中
运行launch文件: roslaunch 功能包名 launch文件名
<node>     ---启动节点的标签
<node pkg="" type="" name=""/>   ---pkg功能包名,type可执行文件名,name节点名,会取代原文件节点名,重映射
还有可选属性:output,respawn,required,ns,args ......
<param>      ---设置ros系统中参数服务器的参数,设置一个参数
<param name="" value="" />
<rosparam>   ---读取参数文件中多个参数来设置
<rosparam file="$(find pkg)/config/param.yaml" command="load" ns="params" />

<arg>       ---设置launch文件的局部变量,可被调用
<arg name="arg-name" value="" />
调用:
<param name="param_name" value="$(arg arg-name)" />
<node pkg="" type="" name="" args="$(arg arg-name)" />

<remap>    ---重映射ros资源名,重新对资源命名,命名后原名字就不能用了
<remap from="/turtlebot/cmd_vel"to"/cmd_vel" />
from:原名字
to:映射之后的名字

<include>   ---调用其他launch文件
<include file=""/>
file:其他launch文件路径
----------------------------------------------------------------------

launch文件示例


catkin_create_pkg learning_launch    ---创建功能包
mkdir launch                        ---在功能包创建文件夹方便管理launch文件
touch simple.launch
----------------------------------------------------------------------
simple.launch:
<launch>
  <node pkg="learning_topic" type="person_publisher" name="publisher" />
  <node pkg="learning_topic" type="person_subscriber" name="subscriber" />
</launch>
----------------------------------------------------------------------
turtlesim_parameter_config.launch:(通过launch文件配置参数)
<launch>
  <param name="turtle_number" value="2">
 
  <node pkg="turtelsim" type="turtelsim_node" name="turtlesim_node" />
    <param name="turtle_1" value="tom" />
    <param name="turtle_2" value="jack" />    
    //在节点中加的参数,会有节点名作为前缀
    
    <rosparam file="$(find learning_launch)/config/param.yaml" command="load" />
    //调用learning_lauch中config文件夹中的param.yaml参数文件
    ----------------------------------------------------------------------

    //yaml文件内容:
    A:123
    B:"HELLO"
    group:
      c:456
      d:""hello"
      //group是命名空间,下面有c,d这两个参数
    ---------------------------------------------------------------------
   </node>
    
  <node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop_key" output=""screen" />
 
</launch>

----------------------------------------------------------------------
start_turtle_tf.launch:(通过launch文件运行广播器和监听器)
<launch>
  <node pkg="turtlesim" type="turtlesim_node" name="turtlesim_node" />
  <node pkg="turtlesim" type="turtle_teleop_key" name="key" output="screen" />
 
  <node pkg="learning_tf" type="turtle_tf_broadcaster" name="turtle1_tf_broadcaster" args="/turtle1"/>
  <node pkg="learning_tf" type="turtle_tf_broadcaster" name="turtel2_tf_broadcaster" args="/turtle2"/>
  <node pkg="learning_tf" type="turtle_tf_listener" name="turtle_tf_listener" />
</launch>
----------------------------------------------------------------------
turtlesim_remap.launch
<launch>
  <include file="$(find learning_launch)/launch/simpie.launch" />  //调用simple.launch文件
  <node pkg="turtlesim" type="turtleism_node" name="turtlesim_node" />
    <remap from="/turtel1/cmd_vel"to"/cmd_vel" />
  </node>
</launch>
----------------------------------------------------------------------

常用可视化工具


QT工具箱   ---基于qt的可视化工具


rqt_graph
rqt_console   ---显示日志,可以进行筛选
rqt_plot      ---数据绘图
rqt_image_view   ---显示摄像头图像,渲染
rqt        ---综合工具,集成了rqt的所有工具

rviz        ---数据3维可视化工具


roscore
rosrun rviz rviz
或者直接 rviz

Gazebo     ---3维物理仿真平台


要进行配置才能使用

roslaunch gazebo_ros empty_world.launch

ROS相关资源网站

ROS:https://www.ros.org
ROS Wiki : http://wiki.ros.org/

ROSCon 2012~2019 : https://pscon.ros.org
ROS Robots : https://robots.ros.org/
Ubuntu Wiki : https://wiki.ubuntu.org.cn

古月居:http://www.guyuehome.com
古月居泡泡:https://www.guyuehome.com/Bubble

古月学院:https://class.guyuehome.com
 

终端工具:Terminator 

主要是方便终端分屏

sudo apt install terminator

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值