ROS的学习1

一.安装ROS

1.添加ROS软件源

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

2.添加密钥

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654

3.安装ROS

sudo apt update
sudo apt-get install ros-melodic-desktop-full

根据Ubuntu的版本选择合适的ROS版本,我的18.04选择Melodic

4.初始化rosdep

sudo rosdep init
rosdep update

 5.设置环境变量

echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

6.安装rosinstall

sudo apt-get install python-rosinstall python-rosinstall-generator python-wstool build-essential

7.ROS启动!!!(初试小海龟)

7.1启动ROS Master

roscore

7.2启动小海龟仿真器

rosrun turtlesim turtlesim_node

7.3控制海龟控制节点

rosrun turtlesim turtle_teleop_key

7.4效果图

二.话题

话题通讯模型分为三个角色1.ROS Master(管理者)2.Talker(发布者)3.Listener(订阅者)

Taker 和Listener启动后,会通过RPC在ROS Master中注册自身信息,ROS Master 负责保管 Talker 和 Listener 注册的信息,并匹配话题相同的 Talker 与 Listener,帮助 Talker 与 Listener 建立连接(1.ROS Master向Listener发送Taker 的RPC地址2.Listener通过RPC向Talker发送连接请求3.Talker接收到请求后通过RPC确认连接并发送自己的TCP地址信息,注意换成了TCP4.使用了TCP建立了连接),连接建立后,Talker 可以发布消息,且发布的消息会被 Listener 订阅。

 在工作空间生成一个功能包,添加依赖 roscpp rospy std_msgs

 配置CMakeLists.txt

add_executable(发布方文件
  src/发布方文件.cpp
)
add_executable(订阅方文件
  src/订阅方文件.cpp
)

target_link_libraries(发布方文件
  ${catkin_LIBRARIES}
)
target_link_libraries(订阅方文件
  ${catkin_LIBRARIES}
)

 发布者代码

#include "ros/ros.h"    
#include "iostream"
#include "std_msgs/String.h"

int main(int argc, char *argv[])
{
    //设置编码,这东西可以解除汉字乱码。
    setlocale(LC_ALL,"");

    // 初始化 ROS 节点
    // 参数1和参数2 后期为节点传值会使用
    // 参数3 是节点名称
    ros::init(argc,argv,"Publisher");   

    // 实例化ROS节点句柄
    ros::NodeHandle n;  

    //  实例化发布者对象
    ros::Publisher fibonacci_pub = n.advertise<std_msgs::String>("/fibonacci",100);

    // 组织被发布的数据,并编写逻辑发布数据
    std_msgs::String msg;

    int num = 1;
    int temp = 0;

    //设置循环频率
    ros::Rate time(10);
    ros::Rate time1(1);

    time1.sleep();

    while(ros::ok())
    {
        //发布消息
        std::stringstream ss;
        ss<<num;
        msg.data = ss.str();
        fibonacci_pub.publish(msg);
        //打印发送的消息
        ROS_INFO("发送数据:%s",msg.data.c_str());
        int former = num;
        num+=temp;
        temp=former;
        //设置休眠时间
        time.sleep();
    }

    return 0;
}

订阅者代码

#include "ros/ros.h"    
#include "std_msgs/String.h" 

void callBack(const std_msgs::String::ConstPtr &msg)
{
    //通过msg获取并操作订阅到的数据
    ROS_INFO("订阅到的数:%s",msg->data.c_str());
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");

    //2.初始化ROS节点
    ros::init(argc,argv,"Subscriber");

    //3.实例化ROS节点句柄
    ros::NodeHandle n;

    //4.实例化发布者对象
    ros::Subscriber fibonacci_sub = n.subscribe<std_msgs::String>("/fibonacci",100,callBack);

    //6.设置循环调用回调函数
    ros::spin();   

    return 0;
}

结果

2.服务通讯模型

服务通讯涉及的三个角色是

  • ROS master(管理者)
  • Server(服务端)
  • Client(客户端)

同样Server和Client启动后通过RPC在ROS Master中注册自身信息, ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client(通过RPC向Client发送Server的TCP地址信息),帮助 Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。(相对于话题,感觉连接更快捷而且有返回)

课后

依赖还是 roscpp rospy std_msgs

定义srv文件

服务通信中,数据分成两部分,请求与响应,在 srv 文件中请求和响应使用---分割,具体实现如下:

功能包下新建 srv 目录,添加 某某某.srv 文件,内容:

# 客户端请求时发送的两个数字
int32 num1
int32 num2
---
# 服务器响应发送的数据
int32 sum
编辑配置文件

package.xml中添加编译依赖与执行依赖

<build_depend>message_generation</build_depend>
  <exec_depend>message_runtime</exec_depend>

CMakeLists.txt编辑 srv 相关配置

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
# 需要加入 message_generation,必须有 std_msgs
add_service_files(
  FILES
  AddInts.srv
)
generate_messages(
  DEPENDENCIES
  std_msgs
)
add_executable(服务端文件 src/服务端文件.cpp)
add_executable(客户端文件 src/客户端文件.cpp)


add_dependencies(服务端文件 ${PROJECT_NAME}_gencpp)
add_dependencies(客户端文件 ${PROJECT_NAME}_gencpp)


target_link_libraries(服务端文件
  ${catkin_LIBRARIES}
)
target_link_libraries(客户端文件
  ${catkin_LIBRARIES}
)
 

 服务端代码

#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"

bool doNums(plumbing_server_client::AddInts::Request &request,plumbing_server_client::AddInts::Response &responce)
{
    //a处理请求
    int num1=request.num1;
    int num2=request.num2;
    ROS_INFO("受到的请求数据:a=%d,b=%d",num1,num2);
    //b组织响应
    int sum=num1+num2;
    responce.sum=sum;
    ROS_INFO("求得的结果是:%d",sum);

    return true;
}
int main(int argc,char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化ros节点
    ros::init(argc,argv,"heishui");//节点名字需要保证唯一
    // 3.创建节点句柄
    ros::NodeHandle nh;
    // 4.创建服务对象
    ros::ServiceServer server=nh.advertiseService("addInts",doNums);
    ROS_INFO("服务器端启动");
    // 6.spin() 
    ros::spin();
    return 0;
}

客服端代码

#include "ros/ros.h"
#include "plumbing_server_client/AddInts.h"

int main(int argc,char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化ros节点
    ros::init(argc,argv,"dabao");
    // 3.创建节点句柄
    ros::NodeHandle nh;
    // 4.创建客户端对象
    ros::ServiceClient client= nh.serviceClient<plumbing_server_client::AddInts>("addInts");
    // 5.提交请求并处理响应
    // 5.1 组织请求
    plumbing_server_client::AddInts ai;
    ai.request.num1=3;
    ai.request.num2=9;
    // 5.2 处理响应
    bool flag =client.call(ai);
    if(flag)
    {
        ROS_INFO("响应成功!");
        //获取结果
        ROS_INFO("%d",ai.response.sum);
    }else
    {
        ROS_INFO("响应失败!");
    }

    return 0;
}

结果

四.动作

action 是一种类似于服务通信的实现,其实现模型也包含请求和响应,但是不同的是,在请求和响应的过程中,服务端还可以连续的反馈当前任务进度,客户端可以接收连续反馈并且还可以取消任务。

  • goal:目标任务;
  • cacel:取消任务;
  • status:服务端状态;
  • result:最终执行结果(只会发布一次);
  • feedback:连续反馈(可以发布多次)。
添加的依赖roscpp rospy std_msgs actionlib actionlib_msgs

然后功能包下新建 action 目录,新增 Xxx.action(比如:AddInts.action)。

action 文件内容组成分为三部分:请求目标值、最终响应结果、连续反馈,三者之间使用---分割示例内容如下:

#目标值
int32 num
---
#最终结果
int32 result
---
#连续反馈
float64 progress_bar

配置CMakeLists.txt

find_package
(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  actionlib
  actionlib_msgs
)
add_action_files(
  FILES
  刚刚自定义的.action
)
generate_messages(
  DEPENDENCIES
  std_msgs
  actionlib_msgs
)
catkin_package(

#  INCLUDE_DIRS include
#  LIBRARIES demo04_action

 CATKIN_DEPENDS roscpp rospy std_msgs actionlib actionlib_msgs

#  DEPENDS system_lib

)
add_executable(服务端文件 src/服务端文件.cpp)
add_executable(客户端文件 src/客户端文件.cpp)
...

add_dependencies(服务端文件 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(客户端文件 ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
...

target_link_libraries(服务端文件
  ${catkin_LIBRARIES}
)
target_link_libraries(客户端文件
  ${catkin_LIBRARIES}
)

服务端代码

#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"
#include "demo01_action/AddIntsAction.h"

typedef actionlib::SimpleActionServer<demo01_action::AddIntsAction> Server;


void cb(const demo01_action::AddIntsGoalConstPtr &goal,Server* server){
    //获取目标值
    int num = goal->num;
    ROS_INFO("目标值:%d",num);
    //累加并响应连续反馈
    int result = 0;
    demo01_action::AddIntsFeedback feedback;//连续反馈
    ros::Rate rate(1);//通过频率设置休眠时间
    for (int i = 1; i <= num; i++)
    {
        //组织连续数据并发布
        feedback.progress_bar = i / (double)num;
        server->publishFeedback(feedback);
        rate.sleep();
    }
    //设置最终结果
    demo01_action::AddIntsResult r;
    r.result = result;
    server->setSucceeded(r);
    ROS_INFO("检测完成");
}

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    ROS_INFO("action服务端实现");
    // 2.初始化ROS节点;
    ros::init(argc,argv,"AddInts_server");
    // 3.创建NodeHandle;
    ros::NodeHandle nh;
    // 4.创建action服务对象;
    /*SimpleActionServer(ros::NodeHandle n, 
                        std::string name, 
                        boost::function<void (const demo01_action::AddIntsGoalConstPtr &)> execute_callback, 
                        bool auto_start)
    */
    // actionlib::SimpleActionServer<demo01_action::AddIntsAction> server(....);
    Server server(nh,"addInts",boost::bind(&cb,_1,&server),false);
    server.start();
    // 5.处理请求,产生反馈与响应;

    // 6.spin().   
    ros::spin();
    return 0;
}

客户端代码

#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"
//#include "demo01_action/AddIntsAction.h"
#include"/home/robolabccz/demo08_ws/devel/include/demo01_action/AddIntsAction.h"

typedef actionlib::SimpleActionClient<demo01_action::AddIntsAction> Client;


//处理最终结果
void done_cb(const actionlib::SimpleClientGoalState &state, const demo01_action::AddIntsResultConstPtr &result){
    if (state.state_ == state.SUCCEEDED)
    {
        ROS_INFO("最终结果:%d",result->result);
    } else {
        ROS_INFO("任务失败!");
    }

}
//服务已经激活
void active_cb(){
    ROS_INFO("服务已经被激活....");
}
//处理连续反馈
void  feedback_cb(const demo01_action::AddIntsFeedbackConstPtr &feedback){
    ROS_INFO("已检测%.0f个当前进度:%.2f", feedback->progress_bar*40,feedback->progress_bar);
}


int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"");
    // 2.初始化ROS节点;
    ros::init(argc,argv,"AddInts_client");
    // 3.创建NodeHandle;
    ros::NodeHandle nh;
    // 4.创建action客户端对象;
    // SimpleActionClient(ros::NodeHandle & n, const std::string & name, bool spin_thread = true)
    // actionlib::SimpleActionClient<demo01_action::AddIntsAction> client(nh,"addInts");
    Client client(nh,"addInts",true);
    //等待服务启动
    client.waitForServer();
    // 5.发送目标,处理反馈以及最终结果;
    /*  
        void sendGoal(const demo01_action::AddIntsGoal &goal, 
            boost::function<void (const actionlib::SimpleClientGoalState &state, const demo01_action::AddIntsResultConstPtr &result)> done_cb, 
            boost::function<void ()> active_cb, 
            boost::function<void (const demo01_action::AddIntsFeedbackConstPtr &feedback)> feedback_cb)

    */
    demo01_action::AddIntsGoal goal;
    goal.num = 40;

    client.sendGoal(goal,&done_cb,&active_cb,&feedback_cb);
    // 6.spin().
    ros::spin();
    return 0;
}

结果截图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值