Ros初步工程

建立工作空间

工作空间( workspace)是一个存放工程开
发相关文件的文件夹。

  • src:代码空间( Source space)
  • build:编译空间( Build space)
  • devel:开发空间(Development space)
  • install:安装空间(instal Space)
    catkin编译系统的目录结构

创建工作空间

初始化工作空间

 mkdir ./ros/catkin_ws/src -p
cd ./ros/catkin_ws/src
catkin_init_workspace

编译工作空间

cd ..
catkin_make

在 工作空间生成二个个文件夹builddevel

设置环境变量

将工作空间的环境变量注入进终端的环境变量

vi ~/.bashrc(或者.zshrc)
source xxx(工作空间的路径)/devel/setup.bash(或者setup.zsh)
# 使当前终端生效
source ~/.bashrc(.zshrc) 

也是在当前终端激活, 但在其他终端无效

source ./devel/setup.bash(或者setup.zsh)

测试环境变量

echo $ROS_PACKAGE_PATH

看当前目录的src是否在环境变量

创建功能包并编译

cd src
# catkin_create_pkg 包名 依赖1 依赖2...
catkin_create_pkg learning_communication std_msgs rospy roscpp
# 返回编译
cd ..
catkin_make
# 刷新环境变量
source ~/.bashrc(.zshrc) 

记住二点:
- 同一个工作空间下,不允许存在同名功能包
- 不同工作空间下,允许存在同名功能包

工作空间的覆盖

  • 工作空间的路径依次在ROS_ PACKAGE PATH环境变量中记录
  • 新设置的路径在ROS_ PACKAGE PATH中会自动放置在最前端
  • 运行时,ROS会优先查找最前端的工作空间中是否存在指定的功能包
  • 如果不存在,就顺序向后查找其他工作空间

ROS 通信编程

话题编程

话题编程模型

创建发布者

learning_src/talker.cc文件

//
// Created by 19842 on 10/21/2019.
//
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"


int main(int args, char **argv){

    // ros节点初始化
    ros::init(args, argv, "talker");

    // 创建节点句柄
    ros::NodeHandle n;
    // 创建第一个publisher, 并发布"chatter"的话题, 消息类型是std_msgs::String
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

    // 设置循环频率 100ms
    ros::Rate loop_rate(10);

    int count = 0;
    while (ros::ok()){
        std_msgs::String msg;
        std::stringstream ss;
        ss << "Hello World:: " << count << std::endl;
        msg.data = ss.str();

        // 发布消息
        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);

        // 循环等待回调函数
        ros::spinOnce();
        // 按照循环频率延时
        loop_rate.sleep();
        ++count;
    }
    return 0;
}

创建订阅者

learning_src/listener.cc文件

//
// Created by 19842 on 10/21/2019.
//
#include "ros/ros.h"
#include "std_msgs/String.h"

// 接收消息后的回调函数
void chatterCallBack(const std_msgs::String::ConstPtr& msg){
    ROS_INFO("I heard: %s", msg->data.c_str());
}

int main(int args, char **argv){

    // ros节点初始化
    ros::init(args, argv, "listener");

    // 创建节点句柄
    ros::NodeHandle n;
    // 创建第一个subscriber, 并订阅"chatter"的话题, 消息类型是std_msgs::String
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallBack);

    ros::spin();

    return 0;
}

测试

在工作空间
1.启动roscore
roscore
2. 启动 发布者rosrun learning_communication talker
3. 启动 订阅者rosrun learning_communication listener
4. 发布者显示 [ INFO] [1571668965.105450200]: Hello World:: \d
订阅者显示[ INFO] [1571668960.706512100]: I heard: Hello World:: 377
则成功

自定义话题消息

在包空间创建msg文件存放消息文件, 新建Person文件

string name
uint8 sex
uint8 age

uint8 unknown=0
uint8 female=1
uint8 male=2

package.xml注入依赖

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

CmakeLists.txtx添加编译依赖

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

add_message_files(
        FILES
        Person.msg
)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
)

返回工作空间重新编译

catkin_make

注意 generat_messages 必须在add_message_filescatkin_package之间
执行rosmsg show Person 出现描述文本就证明定义成功

服务编程

服务通信模型
下面开始一个官方实例, 演示客户端发送二个数, 服务端返回二数之和

准备工作

包空间中在/src新建server.ccclient.cc
在包空间创建msg文件存放消息文件, 新建Person文件

# request
uint64 a
uint64 b
---
# response
uint64 sum

注意---, 这个划分响应体和请求头的参数, 在后面的编程也有体现
package.xml注入依赖

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

CmakeLists.txtx添加编译依赖

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
add_service_files(FILES AddTwoInts.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime)
add_executable(server src/server.cc)
add_executable(client src/client.cc)
target_link_libraries(server
 ${catkin_LIBRARIES}
)
target_link_libraries(client
 ${catkin_LIBRARIES}
)
add_dependencies(server ${PROJECT_NAME}_gencpp)
add_dependencies(client ${PROJECT_NAME}_gencpp)

返回工作空间重新编译

catkin_make

通过后开始码

server编程

#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

/**
 * @brief   service的回调函数,
 * @param req 输入参数, 服务器的请求参数 与`AddTwoInts.srv`的`---`上方对应
 * @param res 输出参数, 服务器的响应参数 与`AddTwoInts.srv`的`---`下方对应
 * @return
 */
bool add(learning_communication::AddTwoInts::Request &req,
         learning_communication::AddTwoInts::Response &res){
    // 可以看出res:响应体 req:请求体
    res.sum = req.a + req.b;
    ROS_INFO("request: x=%ld, y=%ld",(long int)req. a, (long int)req. b);
    ROS_INFO("sending back response: %ld]",(long int)res.sum);
    return true;
}

int main(int args, char **argv){

    // ros节点初始化
    ros::init(args, argv, "add_two_ints_server");

    // 创建节点句柄
    ros::NodeHandle n;
    // 创建service, 并注册一个回调函数add
    ros::ServiceServer service = n.advertiseService("add_two_ints", add);

    ROS_INFO("ready add two ints.");
    ros::spin();
    return 0;
}

client

//
// Created by 19842 on 10/22/2019.
//

#include "ros/ros.h"
// 在 devel/include/
#include "learning_communication/AddTwoInts.h"


int main(int args, char **argv){
    if(args != 3){
        ROS_ERROR("ERROR:: Need three arguments");
        return 1;
    }
    // ros节点初始化
    ros::init(args, argv, "add_two_ints_client");

    // 创建节点句柄
    ros::NodeHandle n;
    // 创建client
    ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
    learning_communication::AddTwoInts srv;
    srv.request.a = atoll(argv[1]);
    srv.request.b = atoll(argv[2]);

    // call默认堵塞
    if(client.call(srv)){
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
    }else{
        ROS_ERROR("ERROR!!");
        return 1;
    }
    return 0;
}

在工作空间, 重新编译并通过后继续

测试

  1. 启动rosmaster, roscore
  2. 启动server, rosrun learning_communication server
  3. 测试client, rosrun learning_communication client 2 3 出现 INFO] [1571708221.767366300]: Sum: 5 则成功

动作编程(参数编程)

动作通信模型
演示如何自定义动作(洗盘子)

准备工作

包空间中在/src新建DoDishes_server.ccDoDishes_client.cc
在包空间创建action文件存放消息文件, 新建DoDishes.action文件

# 定义目标信息 global
uint32 dishwasher_id
# Specify which dishwasher we want to use
---
# 定义结果信息 result
uint32 total_dishes_cleaned
---
# 定义周期反馈的消息 feedback
float32 percent_complete

package.xml注入依赖

<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>

CmakeLists.txtx添加编译依赖

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)
add_action_files(DIRECTORY action FILES DoDishes.action)
generate_messages(DEPENDENCIES std_msgs actionlib_msgs)
catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime)
add_executable(DoDishes_server src/DoDishes_server.cc)
add_executable(DoDishes_client src/DoDishes_client.cc)
target_link_libraries(DoDishes_server
 ${catkin_LIBRARIES}
)
target_link_libraries(DoDishes_client
 ${catkin_LIBRARIES}
)
add_dependencies(DoDishes_server ${${PROJECT_NAME}_EXPORTED_TARGETS})
add_dependencies(DoDishes_client ${${PROJECT_NAME}_EXPORTED_TARGETS})

返回工作空间重新编译

catkin_make

DoDishes_server

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include "learning_communication/DoDishesAction.h"

typedef actionlib::SimpleActionServer<learning_communication::DoDishesAction> Server;

// 收到action的goal后调用该回调函数
void execute(const learning_communication::DoDishesGoalConstPtr& goal, Server* as)
{
    ros::Rate r(1);
    learning_communication::DoDishesFeedback feedback;

    ROS_INFO("Dishwasher %d is working.", goal->dishwasher_id);

    // 假设洗盘子的进度,并且按照1hz的频率发布进度feedback
    for(int i=1; i<=10; i++)
    {
        feedback.percent_complete = i * 10;
        as->publishFeedback(feedback);
        r.sleep();
    }

    // 当action完成后,向客户端返回结果
    ROS_INFO("Dishwasher %d finish working.", goal->dishwasher_id);
    as->setSucceeded();
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "do_dishes_server");
    ros::NodeHandle n;

    // 定义一个服务器
    Server server(n, "do_dishes", boost::bind(&execute, _1, &server), false);
    
    // 服务器开始运行
    server.start();

    ros::spin();

    return 0;
}

DoDishes_client

#include <actionlib/client/simple_action_client.h>
#include "learning_communication/DoDishesAction.h"

typedef actionlib::SimpleActionClient<learning_communication::DoDishesAction> Client;

// 当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,
        const learning_communication::DoDishesResultConstPtr& result)
{
    ROS_INFO("Yay! The dishes are now clean");
    ros::shutdown();
}

// 当action激活后会调用该回调函数一次
void activeCb()
{
    ROS_INFO("Goal just went active");
}

// 收到feedback后调用该回调函数
void feedbackCb(const learning_communication::DoDishesFeedbackConstPtr& feedback)
{
    ROS_INFO(" percent_complete : %f ", feedback->percent_complete);
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "do_dishes_client");

    // 定义一个客户端
    Client client("do_dishes", true);

    // 等待服务器端
    ROS_INFO("Waiting for action server to start.");
    client.waitForServer();
    ROS_INFO("Action server started, sending goal.");

    // 创建一个action的goal
    learning_communication::DoDishesGoal goal;
    goal.dishwasher_id = 1;

    // 发送action的goal给服务器端,并且设置回调函数
    client.sendGoal(goal,  &doneCb, &activeCb, &feedbackCb);

    ros::spin();

    return 0;
}

测试

  1. 启动 rosmaster
  2. 启动 DoDishes_server
  3. 启动 DoDishes_client

分布式通讯

ROS_MASTER_URI

关键组件

launch文件

通过launch文件来启动和配置多节点(会自动启动rosmaster)
在这里插入图片描述
launch和node标签

  1. output: 是否有日志输出
  2. respawn: 启动失败是否重试
  3. required: 启动失败整个launch是否结束
  4. ns: 命名空间
  5. args: 传入参数
    参数设置
    重映射和嵌套

TF坐标变换

TF的实现和功能
TF默认可以保存10秒钟的坐标关系
通过一个树结构来实现的, 通过广播TF变换插入树, 通过监听TF变换

QT工具箱

rqt_console
计算图可视化工具
数据绘图工具
参数动态配置工具
如果一个参数更新, 可以让其他引用参数的节点跟着更新, 使我们更好地调试

Rviz可视化平台

Rviz
Rviz是一款三维可视化工具,可以很好的兼容基于ROS软件框架的机器人平台。

  • 在Rviz中,可以使用可扩展标记语言XML对机器人、周围物体等任何实物进行尺寸、质
    量、位置、材质、关节等属性的描述,并且在界面中呈现出来。
  • 同时,Rviz还可以通过图形化的方式,实时显示机器人传感器的信息、机器人的运动状
    态、周围环境的变化等信息。
  • 总而言之,Rviz通过机器人模型参数、机器人发布的传感信息等数据,为用户进行所有
    可监测信息的图形化显示。用户和开发者也可以在Rviz的控制界面下,通过按钮、滑动
    条、数值等方式,控制机器人的行为
    Rviz界面

GaZeBO物理仿真环境

Gazebo
Gazebo界面
Gazebo与Ros

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值