{"id":13616657,"url":"https://github.com/Ewenwan/Ros","last_synced_at":"2025-04-14T03:31:16.708Z","repository":{"id":38233212,"uuid":"102324163","full_name":"Ewenwan/Ros","owner":"Ewenwan","description":"机器人操作系统ROS  语音识别 语义理解 视觉控制 gazebo仿真 雷达建图导航","archived":false,"fork":false,"pushed_at":"2020-06-27T10:20:13.000Z","size":83605,"stargazers_count":1248,"open_issues_count":0,"forks_count":387,"subscribers_count":40,"default_branch":"master","last_synced_at":"2025-04-13T06:43:56.711Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Makefile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ewenwan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-04T06:00:56.000Z","updated_at":"2025-04-11T09:32:22.000Z","dependencies_parsed_at":"2022-07-12T01:30:46.446Z","dependency_job_id":null,"html_url":"https://github.com/Ewenwan/Ros","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ewenwan%2FRos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ewenwan%2FRos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ewenwan%2FRos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ewenwan%2FRos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ewenwan","download_url":"https://codeload.github.com/Ewenwan/Ros/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248815519,"owners_count":21165939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T20:01:31.535Z","updated_at":"2025-04-14T03:31:16.686Z","avatar_url":"https://github.com/Ewenwan.png","language":"Makefile","funding_links":[],"categories":["Makefile"],"sub_categories":[],"readme":"# Learn ROS\n[黑马 ros机器人操作系统](http://robot.czxy.com/docs/ros/arch/)\n\n[ROS，工业自动化，opencv，3d点云，机器学习，机械臂, 智能机器人，机器人分拣](https://github.com/itheima1/robotics-ros)\n\n[中国大学MOOC《机器人操作系统入门》课程代码示例](https://github.com/Ewenwan/ROS-Academy-for-Beginners)\n\n[ROS 1 和 ROS 2 的前世、今生、安装使用说明与资料汇总](https://blog.csdn.net/zhangrelay/article/details/78418393)\n\n[ROS(1和2)机器人操作系统相关书籍、资料和学习路径](https://blog.csdn.net/zhangrelay/article/details/78179097)\n\n[move_base的全局路径规划代码研究1](https://www.cnblogs.com/shhu1993/p/6337004.html)\n\n[move_base的全局路径规划代码研究2](https://www.cnblogs.com/shhu1993/p/6337004.html)\n\n[move_base代码学习一](https://www.cnblogs.com/shhu1993/p/6323699.html)\n\n[octomap中3d-rrt路径规划](https://www.cnblogs.com/shhu1993/p/7062099.html)\n\n[ROS多个master消息互通](https://www.cnblogs.com/shhu1993/p/6021396.html)\n\n[roscpp源码阅读](https://www.cnblogs.com/shhu1993/p/5573926.html)\n\n[ros的源码阅读](https://www.cnblogs.com/shhu1993/p/5573925.html)\n\n[Gazebo Ros入门](https://www.cnblogs.com/shhu1993/p/5067749.html)\n\n[ROS源代码分析、笔记和注释](https://github.com/Ewenwan/ROS----ros_comm)\n\n[ROS学习资料汇总 ](https://github.com/sychaichangkun/ROS_Resources)\n\n[古月居](https://mp.weixin.qq.com/s?__biz=MzIyMzkxODg0Mw==\u0026mid=2247484445\u0026idx=1\u0026sn=8f10fb4ee78da414588ffabd3eb721a6\u0026chksm=e817ab89df60229f5888a2ec660649d81f371f16f7eff60b982e78fea0a6fe1c0762bc433e15\u0026mpshare=1\u0026scene=1\u0026srcid=1023JPEqq835Iu6CamiVpO2R\u0026pass_ticket=GUYqMrcaykeEbRgrCw0aeD%2BfAzY39PVt%2Bi56mOUARZhCrsvWuLlkpUmDb3YAV5LN#rd)\n\n[ros下开发工具 脚本](https://github.com/carlosmccosta/ros_development_tools)\n\n[ros编程书籍 c++ !!!!推荐](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook)\n\n[Mastering-ROS-for-Robotics-Programming-Second-Edition 代码](https://github.com/PacktPublishing/Mastering-ROS-for-Robotics-Programming-Second-Edition)\n\n[第十四届全国大学生智能汽车竞赛室外光电竞速创意赛,ART-Racecar  ros 激光雷达+IMU建图导航](https://github.com/Ewenwan/racecar)\n\n# 感谢支持\n\n![](https://github.com/Ewenwan/EwenWan/blob/master/zf.jpg)\n\n# 一、消息\n\n## 1. 发布 字符串 消息\n```c\n#include \"ros/ros.h\"\n#include \"std_msgs/String.h\"// 字符串消息 其他 int.h\n#include \u003csstream\u003e\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"example1a\");// 节点初始化\n  ros::NodeHandle n;\n  ros::Publisher pub = n.advertise\u003cstd_msgs::String\u003e(\"message\", 100);// 发布消息到 message 话题，100个数据空间\n  ros::Rate loop_rate(10);// 发送频率\n \n  while (ros::ok())\n  {\n    std_msgs::String msg;\n    std::stringstream ss;\n    ss \u003c\u003c \"Hello World!\"; // 生成消息\n    msg.data = ss.str();\n    pub.publish(msg);// 发布\n    \n    ros::spinOnce();// 给ros控制权\n    loop_rate.sleep();// 时间没到，休息\n  }\n  return 0;\n}\n\n```\n## 2. 订阅消息\n```c\n\n#include \"ros/ros.h\"\n#include \"std_msgs/String.h\"\n\n// 订阅消息的回调函数\nvoid messageCallback(const std_msgs::String::ConstPtr\u0026 msg)\n{\n  ROS_INFO(\"Thanks: [%s]\", msg-\u003edata.c_str());\n}\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"example1b\");\n  ros::NodeHandle n;\n  // 订阅话题，消息，接收到消息就会 调用 回调函数  messageCallback\n  ros::Subscriber sub = n.subscribe(\"message\", 100, messageCallback);\n  ros::spin();\n  return 0;\n}\n\n```\n## 3. 发布自定义消息 msg\n```c\n#include \"ros/ros.h\"\n#include \"chapter2_tutorials/chapter2_msg.h\" // 项目 msg文件下\n\n// msg/chapter2_msg.msg  包含3个整数的消息\n// int32 A\n// int32 B\n// int32 C\n\n#include \u003csstream\u003e\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"example2a\");\n  ros::NodeHandle n;\n  // 发布自定义消息====\n  ros::Publisher pub = n.advertise\u003cchapter2_tutorials::chapter2_msg\u003e(\"chapter2_tutorials/message\", 100);\n  ros::Rate loop_rate(10);\n  while (ros::ok())\n  {\n    chapter2_tutorials::chapter2_msg msg;\n    msg.A = 1;\n    msg.B = 2;\n    msg.C = 3;\n    \n    pub.publish(msg);\n    ros::spinOnce();\n   \n    loop_rate.sleep();\n  }\n  return 0;\n}\n\n```\n\n\n## 4. 订阅自定义消息 msg\n```c\n#include \"ros/ros.h\"\n#include \"chapter2_tutorials/chapter2_msg.h\"\n\nvoid messageCallback(const chapter2_tutorials::chapter2_msg::ConstPtr\u0026 msg)\n{\n  ROS_INFO(\"I have received: [%d] [%d] [%d]\", msg-\u003eA, msg-\u003eB, msg-\u003eC);\n}\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"example3_b\");\n  ros::NodeHandle n;\n  // 订阅自定义消息===\n  ros::Subscriber sub = n.subscribe(\"chapter2_tutorials/message\", 100, messageCallback);\n  ros::spin();\n  return 0;\n}\n\n```\n\n## 5. 发布自定义服务 srv\n```c\n#include \"ros/ros.h\"\n#include \"chapter2_tutorials/chapter2_srv.h\" // 项目 srv文件下\n// chapter2_srv.srv\n// int32 A    请求\n// int32 B \n// --- \n// int32 sum  响应---该服务完成求和服务\n\n// 服务回调函数==== 服务提供方具有 服务回调函数\nbool add(chapter2_tutorials::chapter2_srv::Request  \u0026req, // 请求\n         chapter2_tutorials::chapter2_srv::Response \u0026res) // 回应\n{\n  res.sum = req.A + req.B; // 求和服务\n  ROS_INFO(\"Request: A=%d, B=%d\", (int)req.A, (int)req.B);\n  ROS_INFO(\"Response: [%d]\", (int)res.sum);\n  return true;\n}\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"adder_server\");\n  ros::NodeHandle n;\n  // 发布服务(打广告) 广而告之 街头叫卖   等待被撩.jpg\n  ros::ServiceServer service = n.advertiseService(\"chapter2_tutorials/adder\", add);\n  ROS_INFO(\"adder_server has started\");\n  ros::spin();\n\n  return 0;\n}\n\n```\n\n## 6. 订阅服务 获取服务 强撩.jpg\n```c\n#include \"ros/ros.h\"\n#include \"chapter2_tutorials/chapter2_srv.h\"\n#include \u003ccstdlib\u003e\n\nint main(int argc, char **argv)\n{\n  ros::init(argc, argv, \"adder_client\");\n  if (argc != 3)\n  {\n    ROS_INFO(\"Usage: adder_client A B \");\n    return 1;\n  }\n\n  ros::NodeHandle n;\n  // 服务客户端，需求端，调用服务\n  ros::ServiceClient client = n.serviceClient\u003cchapter2_tutorials::chapter2_srv\u003e(\"chapter2_tutorials/adder\");\n  \n  //创建服务类型\n  chapter2_tutorials::chapter2_srv srv;\n  \n  // 设置请求内容\n  srv.request.A = atoll(argv[1]);\n  srv.request.B = atoll(argv[2]);\n  \n  // 调用服务===\n  if (client.call(srv))\n  {\n    // 打印服务带有的响应数据====\n    ROS_INFO(\"Sum: %ld\", (long int)srv.response.sum);\n  }\n  else\n  {\n    ROS_ERROR(\"Failed to call service adder_server\");\n    return 1;\n  }\n\n  return 0;\n}\n\n```\n\nCMakeLists.txt\n\n```c\ncmake_minimum_required(VERSION 2.8.3)\nproject(chapter2_tutorials) # 项目名称\n## 依赖包===========\nfind_package(catkin REQUIRED COMPONENTS\n  roscpp\n  std_msgs\n  message_generation  # 生成自定义消息的头文件\n  dynamic_reconfigure\n)\n## 自定义消息文件====\nadd_message_files(\n\tFILES\n\tchapter2_msg.msg\n)\n\n## 自定义服务文件====\nadd_service_files(\n\tFILES\n\tchapter2_srv.srv\n)\n\n## 生成消息头文件\ngenerate_messages(\n   DEPENDENCIES\n   std_msgs\n)\n## 依赖\ncatkin_package(\nCATKIN_DEPENDS message_runtime\n)\n\n## 编译依赖库文件\ninclude_directories(\n  include\n  ${catkin_INCLUDE_DIRS}\n)\n\n# 创建可执行文件\nadd_executable(example1a src/example_1a.cpp)\nadd_executable(example1b src/example_1b.cpp)\n\nadd_executable(example2a src/example_2a.cpp)\nadd_executable(example2b src/example_2b.cpp)\n\nadd_executable(example3a src/example_3a.cpp)\nadd_executable(example3b src/example_3b.cpp)\n## 添加依赖\nadd_dependencies(example1a chapter2_tutorials_generate_messages_cpp)\nadd_dependencies(example1b chapter2_tutorials_generate_messages_cpp)\n\nadd_dependencies(example2a chapter2_tutorials_generate_messages_cpp)\nadd_dependencies(example2b chapter2_tutorials_generate_messages_cpp)\n\nadd_dependencies(example3a chapter2_tutorials_generate_messages_cpp)\nadd_dependencies(example3b chapter2_tutorials_generate_messages_cpp)\n\n# 动态链接库\ntarget_link_libraries(example1a ${catkin_LIBRARIES})\ntarget_link_libraries(example1b ${catkin_LIBRARIES})\n\ntarget_link_libraries(example2a ${catkin_LIBRARIES})\ntarget_link_libraries(example2b ${catkin_LIBRARIES})\n\ntarget_link_libraries(example3a ${catkin_LIBRARIES})\ntarget_link_libraries(example3b ${catkin_LIBRARIES})\n\n```\n\n# 二、行动action类型 参数服务器 坐标变换 tf可视化 安装插件 gazebo仿真\n[插件1]\n(https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/tree/master/Chapter03/chapter3_tutorials/nodelet_hello_ros)\n\n[插件2](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter03/chapter3_tutorials/pluginlib_tutorials/src/polygon_plugins.cpp)\n\n## 1. 发布行动 action\n// 类似于服务，但是是应对 服务任务较长的情况，避免客户端长时间等待，\n\n// 以及服务结果是一个序列，例如一件工作先后很多步骤完成\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cactionlib/server/simple_action_server.h\u003e // action 服务器\n#include \u003cactionlib_tutorials/FibonacciAction.h\u003e   // 自定义的 action类型 产生斐波那契数列 \n// action/Fibonacci.action\n// #goal definition        任务目标\n// int32 order\n// ---\n// #result definition      最终 结果\n// int32[] sequence\n// ---\n// #feedback               反馈 序列 记录中间 递增 序列\n// int32[] sequence\n\n//  定义的一个类========================\nclass FibonacciAction\n{\n// 私有=============\nprotected:\n  ros::NodeHandle nh_; // 节点实例\n  \n  // 节点实例必须先被创建 NodeHandle instance \n  actionlib::SimpleActionServer\u003cactionlib_tutorials::FibonacciAction\u003e as_; // 行动服务器，输入自定义的模板类似\n  std::string action_name_;// 行动名称\n  \n  // 行动消息，用来发布的 反馈feedback / 结果result\n  actionlib_tutorials::FibonacciFeedback feedback_;\n  actionlib_tutorials::FibonacciResult result_;\n  \n// 公开==================\npublic:\n  // 类构造函数=============\n  FibonacciAction(std::string name) :\n    // 行动服务器 需要绑定 行动回调函数===FibonacciAction::executeCB====\n    as_(nh_, name, boost::bind(\u0026FibonacciAction::executeCB, this, _1), false),\n    action_name_(name)\n  {\n    as_.start();// 启动\n  }\n  // 类析构函数========\n  ~FibonacciAction(void)\n  {\n  }\n  //  行动回调函数=========\n  void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr \u0026goal)\n  {\n  \n    ros::Rate r(1);// 频率\n    bool success = true;// 标志\n\n    /* the seeds for the fibonacci sequence */\n    feedback_.sequence.clear();// 结果以及反馈\n    feedback_.sequence.push_back(0); // 斐波那契数列\n    feedback_.sequence.push_back(1);\n\n    ROS_INFO(\"%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i\", action_name_.c_str(), goal-\u003eorder, feedback_.sequence[0], feedback_.sequence[1]);\n\n    /* start executing the action */\n    for(int i=1; i\u003c=goal-\u003eorder; i++)// order 为序列数量\n    {\n      /* check that preempt has not been requested by the client */\n      if (as_.isPreemptRequested() || !ros::ok())\n      {\n        ROS_INFO(\"%s: Preempted\", action_name_.c_str());\n\t\t\n        /* set the action state to preempted */\n        as_.setPreempted();\n        success = false;\n        break;\n      }\n      // 产生后一个数 \n      feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);\n      \n\t  /* publish the feedback */\n      as_.publishFeedback(feedback_);// 发布\n      /* this sleep is not necessary, however, the sequence is computed at 1 Hz for demonstration purposes */\n      r.sleep();\n    }\n\n    if(success)\n    {\n      // 最终结果\n      result_.sequence = feedback_.sequence;\n      ROS_INFO(\"%s: Succeeded\", action_name_.c_str());\n      \n\t  /* set the action state to succeeded */\n      as_.setSucceeded(result_);\n    }\n  }\n\n\n};\n\n\nint main(int argc, char** argv)\n{\n  ros::init(argc, argv, \"fibonacci server\");\n\n  FibonacciAction fibonacci(\"fibonacci\");\n  ros::spin();\n\n  return 0;\n}\n\n```\n\n\n## 2. 行动客户端 类似 服务消费者\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cactionlib/client/simple_action_client.h\u003e// action 客户端\n#include \u003cactionlib/client/terminal_state.h\u003e      // action 状态\n#include \u003cactionlib_tutorials/FibonacciAction.h\u003e  // 自定义行动类型\n\nint main (int argc, char **argv)\n{\n  ros::init(argc, argv, \"fibonacci client\");\n\n  /* create the action client\n     \"true\" causes the client to spin its own thread */\n  //  action 客户端 =====\n  actionlib::SimpleActionClient\u003cactionlib_tutorials::FibonacciAction\u003e ac(\"fibonacci\", true);\n\n  ROS_INFO(\"Waiting for action server to start.\");\n  \n  /* will be  waiting for infinite time */\n  ac.waitForServer(); // 等待 行动服务器启动\n\n  ROS_INFO(\"Action server started, sending goal.\");\n  \n  // 发布任务目标 产生20个数量的 斐波那契数列序列\n  actionlib_tutorials::FibonacciGoal goal;\n  goal.order = 20;\n  ac.sendGoal(goal);// 发给 行动服务器=====\n\n  // 等待 行动 执行结果\n  bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));\n\n  if (finished_before_timeout)\n  {\n    actionlib::SimpleClientGoalState state = ac.getState();// 状态\n    ROS_INFO(\"Action finished: %s\",state.toString().c_str());\n  }\n  else\n    ROS_INFO(\"Action doesnot finish before the time out.\");\n\n  return 0;\n}\n\n```\n\nCMakeLists.txt\n```c\ncmake_minimum_required(VERSION 2.8.3)\nproject(actionlib_tutorials)\n# add_compile_options(-std=c++11)\n# 找到包依赖\nfind_package(catkin REQUIRED COMPONENTS\n  actionlib\n  actionlib_msgs\n  message_generation\n  roscpp\n  rospy\n  std_msgs\n)\n## 行动自定义文件\nadd_action_files(\n   DIRECTORY action\n   FILES Fibonacci.action\n )\n## 生成行动类型 头文件\ngenerate_messages(\n DEPENDENCIES actionlib_msgs std_msgs\n)\n## 包依赖\ncatkin_package(\n  INCLUDE_DIRS include\n  LIBRARIES actionlib_tutorials\n  CATKIN_DEPENDS actionlib actionlib_msgs message_generation roscpp rospy std_msgs\n  DEPENDS system_lib\n)\n## 包含\ninclude_directories(\n# include\n  ${catkin_INCLUDE_DIRS}\n)\n\n## 编译 连接 \nadd_executable(fibonacci_server src/fibonacci_server.cpp)\nadd_executable(fibonacci_client src/fibonacci_client.cpp)\n\ntarget_link_libraries(fibonacci_server ${catkin_LIBRARIES})\ntarget_link_libraries(fibonacci_client ${catkin_LIBRARIES})\n\nadd_dependencies(fibonacci_server ${actionlib_tutorials_EXPORTED_TARGETS})\nadd_dependencies(fibonacci_client ${actionlib_tutorials_EXPORTED_TARGETS})\n\n```\n\n\n## 3. 参数服务器 parameter_server \n```c\n#include \u003cros/ros.h\u003e\n\n#include \u003cdynamic_reconfigure/server.h\u003e// 动态参数 调整\n#include \u003cparameter_server_tutorials/parameter_server_Config.h\u003e // 自定义的 配置参数列表\n\n// cfg/parameter_server_tutorials.cfg===========\n/*\n# coding:utf-8\n#!/usr/bin/env python\nPACKAGE = \"parameter_server_tutorials\" # 包名\n\nfrom dynamic_reconfigure.parameter_generator_catkin import *\n\ngen = ParameterGenerator()# 参数生成器\n\n# 参数列表 ====================\ngen.add(\"BOOL_PARAM\",   bool_t,   0, \"A Boolean  parameter\",  True) # BOOL量类型参数\ngen.add(\"INT_PARAM\",    int_t,    0, \"An Integer Parameter\",  1,   0, 100) # 整形量参数\ngen.add(\"DOUBLE_PARAM\", double_t, 0, \"A Double   Parameter\",  0.01, 0,   1)# 浮点型变量参数\ngen.add(\"STR_PARAM\",    str_t,    0, \"A String   parameter\",  \"Dynamic Reconfigure\") # 字符串类型变量参数\n\n#  自定义 枚举常量 类型 ==========\nsize_enum = gen.enum([ gen.const(\"Low\",        int_t,  0, \"Low : 0\"),\n                       gen.const(\"Medium\",     int_t,  1, \"Medium : 1\"),\n                       gen.const(\"High\",       int_t,  2, \"Hight :2\")],\n                       \"Selection List\")\n# 添加自定义 变量类型\ngen.add(\"SIZE\", int_t, 0, \"Selection List\", 1, 0, 3, edit_method=size_enum)\n\n# 生成 动态参数配置 头文件   以 parameter_server_ 为前缀\nexit(gen.generate(PACKAGE, \"parameter_server_tutorials\", \"parameter_server_\"))\n\n*/\n\n\n// 参数改变后 的回调函数，parameter_server_Config 为参数头\nvoid callback(parameter_server_tutorials::parameter_server_Config \u0026config, uint32_t level)\n{\n\n  ROS_INFO(\"Reconfigure Request: %s %d %f %s %d\", \n            config.BOOL_PARAM?\"True\":\"False\", \n            config.INT_PARAM, \n            config.DOUBLE_PARAM, \n            config.STR_PARAM.c_str(),\n            config.SIZE);\n\n}\n\nint main(int argc, char **argv) \n{\n  ros::init(argc, argv, \"parameter_server_tutorials\");\n\n  dynamic_reconfigure::Server\u003cparameter_server_tutorials::parameter_server_Config\u003e server;// 参数服务器\n  dynamic_reconfigure::Server\u003cparameter_server_tutorials::parameter_server_Config\u003e::CallbackType f;// 参数改变 回调类型\n  \n  // 绑定回调函数\n  f = boost::bind(\u0026callback, _1, _2);\n  // 参数服务器设置 回调器\n  server.setCallback(f);\n\n  ROS_INFO(\"Spinning\");\n  ros::spin();// 启动\n  return 0;\n}\n\n```\n\n\nCMakeLists.txt\n```c\ncmake_minimum_required(VERSION 2.8.3)\nproject(parameter_server_tutorials)\n# add_compile_options(-std=c++11)\n\n# 找到包\nfind_package(catkin REQUIRED COMPONENTS\n  roscpp\n  std_msgs\n  message_generation\n  dynamic_reconfigure\n)\n# 动态参数配置文件\ngenerate_dynamic_reconfigure_options(\n  cfg/parameter_server_tutorials.cfg\n)\n# 依赖\ncatkin_package(\nCATKIN_DEPENDS message_runtime\n)\n\n# 包含\ninclude_directories(\n  include\n  ${catkin_INCLUDE_DIRS}\n)\n\n# 生成可执行文件\nadd_executable(parameter_server_tutorials src/parameter_server_tutorials.cpp)\nadd_dependencies(parameter_server_tutorials parameter_server_tutorials_gencfg)\ntarget_link_libraries(parameter_server_tutorials ${catkin_LIBRARIES})\n\n```\n\n\n## 4. 坐标变换发布 tf_broadcaster \n```c\n#include \u003cros/ros.h\u003e\n#include \u003ctf/transform_broadcaster.h\u003e // 坐标变换发布/广播\n#include \u003cturtlesim/Pose.h\u003e// 小乌龟位置类型\n\nstd::string turtle_name;\n\n// 小乌龟 位姿 话题 回调函数 =======\nvoid poseCallback(const turtlesim::PoseConstPtr\u0026 msg)\n{\n  static tf::TransformBroadcaster br;// 坐标变换广播\n  tf::Transform transform;// 坐标变换 \n  transform.setOrigin( tf::Vector3(msg-\u003ex, msg-\u003ey, 0.0) );// 坐标位置\n  tf::Quaternion q;// 位姿四元素\n  q.setRPY(0, 0, msg-\u003etheta);// 按照 rpy 姿态向量形式设置 平面上只有 绕Z轴的旋转 偏航角\n  transform.setRotation(q);// 姿态\n  // 广播位姿变换消息=====\n  br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), \"world\", turtle_name));\n}\n\nint main(int argc, char** argv)\n{\n  ros::init(argc, argv, \"tf_broadcaster\");\n  if (argc != 2){ROS_ERROR(\"need turtle name as argument\"); return -1;};\n  turtle_name = argv[1];\n\n  ros::NodeHandle node;\n  // 订阅小乌龟 位姿 话题数据  绑定回调函数 poseCallback\n  ros::Subscriber sub = node.subscribe(turtle_name+\"/pose\", 10, \u0026poseCallback);\n\n  ros::spin();\n  return 0;\n}\n\n\n```\n\n\n## 5. 坐标变换监听 tf_listener \n```c\n#include \u003cros/ros.h\u003e\n#include \u003ctf/transform_listener.h\u003e// 坐标变换监听\n#include \u003cgeometry_msgs/Twist.h\u003e  // 消息类型\n#include \u003cturtlesim/Spawn.h\u003e// 生成一个小乌龟\n\nint main(int argc, char** argv)\n{\n  ros::init(argc, argv, \"tf_listener\");\n\n  ros::NodeHandle node;\n\n  ros::service::waitForService(\"spawn\");// 等待 生成小乌龟的服务到来\n  ros::ServiceClient add_turtle =\n    node.serviceClient\u003cturtlesim::Spawn\u003e(\"spawn\"); // 服务客户端\n  turtlesim::Spawn srv;\n  add_turtle.call(srv); // 调用服务\n  \n  // 发布小乌龟运动指令=====\n  ros::Publisher turtle_vel =\n    node.advertise\u003cgeometry_msgs::Twist\u003e(\"turtle2/cmd_vel\", 10);\n  \n  // 左边变换监听\n  tf::TransformListener listener;\n\n  ros::Rate rate(10.0);\n  while (node.ok())\n  {\n    tf::StampedTransform transform; // 得到的坐标变换消息\n    try\n    {\n      // 两个小乌龟坐标变换消息 之差 左边变换??\n      // 有两个  坐标变换发布器 一个发布 /turtle1  一个发布 /turtle2\n      listener.lookupTransform(\"/turtle2\", \"/turtle1\",\n                               ros::Time(0), transform);\n    }\n    catch (tf::TransformException \u0026ex) \n    {\n      ROS_ERROR(\"%s\",ex.what());\n      ros::Duration(1.0).sleep();\n      continue;\n    }\n    \n    // 根据位姿差，发布 命令 让 小乌龟2 追赶上 小乌龟1\n    geometry_msgs::Twist vel_msg;\n    // 位置差值 计算角度\n    vel_msg.angular.z = 4.0 * atan2(transform.getOrigin().y(),\n                                    transform.getOrigin().x());\n    // 位置直线距离，关联到速度\n    vel_msg.linear.x = 0.5 * sqrt(pow(transform.getOrigin().x(), 2) +\n                                  pow(transform.getOrigin().y(), 2));\n    // 发布速度命令\n    turtle_vel.publish(vel_msg);\n\n    rate.sleep();\n  }\n  return 0;\n}\n\n```\n\nCMakeLists.txt\n```c\ncmake_minimum_required(VERSION 2.8.3)\nproject(tf_tutorials)\n\nfind_package(catkin REQUIRED COMPONENTS\n  roscpp\n  rospy\n  tf\n  turtlesim\n)\n\ncatkin_package()\n\ninclude_directories(\n# include\n  ${catkin_INCLUDE_DIRS}\n)\n\nadd_executable(turtle_tf_broadcaster src/turtle_tf_broadcaster.cpp)\ntarget_link_libraries(turtle_tf_broadcaster ${catkin_LIBRARIES})\n\nadd_executable(turtle_tf_listener src/turtle_tf_listener.cpp)\ntarget_link_libraries(turtle_tf_listener ${catkin_LIBRARIES})\n\n```\n\nstart_demo.launch\n```c\n\u003claunch\u003e\n    \u003c!-- Turtlesim Node 小乌龟1--\u003e\n    \u003cnode pkg=\"turtlesim\" type=\"turtlesim_node\" name=\"sim\"/\u003e\n    \u003c!--  小乌龟1 键盘控制 --\u003e\n    \u003cnode pkg=\"turtlesim\" type=\"turtle_teleop_key\" name=\"teleop\" output=\"screen\"/\u003e\n    \n    \u003c!-- Axes --\u003e\n    \u003cparam name=\"scale_linear\" value=\"2\" type=\"double\"/\u003e\n    \u003cparam name=\"scale_angular\" value=\"2\" type=\"double\"/\u003e\n    \u003c!--  发布 小乌龟1 位姿 -\u003e\n    \u003cnode pkg=\"tf_tutorials\" type=\"turtle_tf_broadcaster\"\n          args=\"/turtle1\" name=\"turtle1_tf_broadcaster\" /\u003e\n    \u003c!--  发布 小乌龟2 位姿 -\u003e\t  \n    \u003cnode pkg=\"tf_tutorials\" type=\"turtle_tf_broadcaster\"\n          args=\"/turtle2\" name=\"turtle2_tf_broadcaster\" /\u003e\n    \u003c!-- 监听两者位姿变换 让小乌龟2 追上 小乌龟1 -\u003e\t  \n    \u003cnode pkg=\"tf_tutorials\" type=\"turtle_tf_listener\"\n          name=\"listener\" /\u003e\n\n  \u003c/launch\u003e\n\n\n```\n\n## 6. 可视化 插件\n[rviz 插件](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter03/chapter3_tutorials/rviz_plugin_tutorials/src/imu_display.cpp)\n\n[gazebo 插件](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter03/chapter3_tutorials/gazebo_plugin_tutorial/hello_world.cc)\n\n\n# 三、日志 + 话题/服务/参数/action/发布图像/发布点云/发布marker\n\n\n## 1. 定义 ROS_DEBUG \n```c\n#include \u003cros/ros.h\u003e\n#include \u003cros/console.h\u003e // 控制台\n\n#define OVERRIDE_NODE_VERBOSITY_LEVEL 0\n\nint main( int argc, char **argv )\n{\n\n  ros::init( argc, argv, \"program1\" );\n\n#if OVERRIDE_NODE_VERBOSITY_LEVEL\n  /* Setting the logging level manually to DEBUG */\n  // 日志等级 Debug\n  ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug);\n#endif\n\n  ros::NodeHandle nh;\n\n  const double val = 3.14;\n\n// ros 打印日志\n  ROS_DEBUG( \"We are looking DEBUG message\" );\n\n  ROS_DEBUG( \"We are looking DEBUG message with an argument: %f\", val );\n\n  ROS_DEBUG_STREAM(\"We are looking DEBUG stream message with an argument: \" \u003c\u003c val);\n\n  ros::spinOnce();\n\n  return EXIT_SUCCESS;\n\n}\n\n\n```\n\n## 2. 各种消息接口 名字消息 条件消息 过滤消息 单次消息 频率消息\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cros/console.h\u003e\n\nint main( int argc, char **argv )\n{\n\n  ros::init( argc, argv, \"program2\" );\n\n  ros::NodeHandle n;\n\n  const double val = 3.14;\n\n  /* Basic messages: 基本消息 */\n  ROS_INFO( \"ROS INFO message.\" ); // \n  ROS_INFO( \"ROS INFO message with argument: %f\", val ); // 相当于c中的printf; \n  ROS_INFO_STREAM( \"ROS INFO stream message with argument: \" \u003c\u003c val); // 相当于c++中的cout; \n\n  /* Named messages: 为调试信息命名 */ \n  // 表示为这段信息命名，为了更容易知道这段信息来自那段代码．\n  ROS_INFO_STREAM_NAMED(\"named_msg\",\"ROS named INFO stream message; val = \" \u003c\u003c val);\n\n  /* Conditional messages: 条件消息*/\n  ROS_INFO_STREAM_COND(val \u003c 0., \"ROS conditional INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003c 0\");\n  ROS_INFO_STREAM_COND(val \u003e= 0.,\"ROS conditional INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003e= 0\");\n\n  /* Conditional Named messages: 条件 名字消息*/\n  ROS_INFO_STREAM_COND_NAMED(val \u003c 0., \"cond_named_msg\",\"ROS conditional INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003c 0\");\n  ROS_INFO_STREAM_COND_NAMED(val \u003e= 0., \"cond_named_msg\",\"ROS conditional INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003e= 0\");\n\n  /* Filtered messages: 滤波消息*/\n  struct ROSLowerFilter : public ros::console::FilterBase \n  {\n    ROSLowerFilter( const double\u0026 val ) : value( val ) {}\n\n    inline virtual bool isEnabled()\n    {\n      return value \u003c 0.;// 小于0\n    }\n\n    double value;\n  };\n\n  struct ROSGreaterEqualFilter : public ros::console::FilterBase\n  {\n    ROSGreaterEqualFilter( const double\u0026 val ) : value( val ) {}\n\n    inline virtual bool isEnabled()\n    {\n      return value \u003e= 0.; // 大于0\n    }\n  \n    double value;\n  };\n\n  ROSLowerFilter filter_lower(val);// 小于0的消息\n  ROSGreaterEqualFilter filter_greater_equal(val);// 大于0的消息\n   \n   // 宏定义接口传入 过滤消息实例================\n  ROS_INFO_STREAM_FILTER(\n    \u0026filter_lower,\n    \"ROS filter INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003c 0\"\n  );\n  ROS_INFO_STREAM_FILTER(\n    \u0026filter_greater_equal,\n    \"ROS filter INFO stream message; val (\" \u003c\u003c val \u003c\u003c \") \u003e= 0\"\n  );\n\n  /* Once messages: 单次显示*/\n  for( int i = 0; i \u003c 10; ++i ) {\n  // 在循环中让信息只输出一次 \n    ROS_INFO_STREAM_ONCE(\n      \"ROS once INFO stream message; i = \" \u003c\u003c i\n    );\n  }\n\n  /* Throttle messages: 设置显示频率 */\n  for( int i = 0; i \u003c 10; ++i ) {\n  // THROTTLE表示节流的意思， 代码运行两次输出一次INFO throttle message． \n    ROS_INFO_STREAM_THROTTLE(\n      2,\n      \"ROS throttle INFO stream message; i = \" \u003c\u003c i\n    );\n    ros::Duration(1).sleep();\n  }\n\n  ros::spinOnce();\n\n  return EXIT_SUCCESS;\n\n}\n\n\n```\n\n\n## 3. debug  info  warn  error  fatal \n```c\n\n#include \u003cros/ros.h\u003e\n#include \u003cros/console.h\u003e\n\nint main( int argc, char **argv )\n{\n\n    ros::init( argc, argv, \"program3\" );\n\n    ros::NodeHandle nh;\n\n    ros::Rate rate(1);\n\n    while(ros::ok())\n    {\n\n        ROS_DEBUG_STREAM( \"ROS DEBUG message.\");  // debug 等级消息\n        ROS_INFO_STREAM ( \"ROS INFO message.\");   // info  普通正常消息\n        ROS_WARN_STREAM ( \"ROS WARN message.\" );  // warn  警告消息\n        ROS_ERROR_STREAM( \"ROS ERROR message.\" ); // error 错误消息\n        ROS_FATAL_STREAM( \"ROS FATAL message.\" ); // fatal 验证错误消息\n\n        ROS_INFO_STREAM_NAMED( \"named_msg\", \"ROS INFO named message.\" );// 名字消息\n\n        ROS_INFO_STREAM_THROTTLE(2, \"ROS INFO Throttle message.\" );     // 频率消息\n\n        ros::spinOnce();\n        rate.sleep();\n    }\n    return EXIT_SUCCESS;\n}\n\n\n```\n\n\n## 4. 自定义服务消息 客户端 + 日志打印   北京瘫.jpg\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cros/console.h\u003e\n\n#include \u003cstd_msgs/Int32.h\u003e\n#include \u003cgeometry_msgs/Vector3.h\u003e\n\n#include \u003cchapter4_tutorials/SetSpeed.h\u003e // 自定义服务消息类型\n// srv/SetSpeed.srv-----------\n// float32 desired_speed   // 请求，期望速度\n// ---\n// float32 previous_speed  // 反馈，上一次的速度\n// float32 current_speed   // 当前速度\n// bool stalled            // 设置完成标志\n\nint main( int argc, char **argv )\n{\n\n    ros::init( argc, argv, \"program4\" );\n\n    ros::NodeHandle nh;\n    \n    // 发布温度数据\n    ros::Publisher pub_temp = nh.advertise\u003c std_msgs::Int32 \u003e( \"temperature\", 1000 );// 普通整形数据话题，温度数据\n    \n    // 发布加速度消息 1*3 向量\n    ros::Publisher pub_accel = nh.advertise\u003c geometry_msgs::Vector3 \u003e( \"acceleration\", 1000 );\n    \n    // 服务客户端，请求服务，获取服务，消费者\n    ros::ServiceClient srv_speed = nh.serviceClient\u003c chapter4_tutorials::SetSpeed\u003e( \"speed\" );\n\n    std_msgs::Int32 msg_temp;// 温度数据\n    geometry_msgs::Vector3 msg_accel;// 三轴加速度消息\n    \n    chapter4_tutorials::SetSpeed msg_speed;// 服务消息\n\n    int i = 0;\n\n    ros::Rate rate( 1 );// 频率为1\n    while( ros::ok() ) \n    {\n\n        msg_temp.data = i;// 温度数据======\n\n        msg_accel.x = 0.1 * i;// 三轴加速度消息===== \n        msg_accel.y = 0.2 * i;\n        msg_accel.z = 0.3 * i;\n        \n        // 服务数据，设置 期望值，消费者提出的服务标准====\n        msg_speed.request.desired_speed = 0.01 * i;// 期望速度===\n\n        pub_temp.publish( msg_temp );// 发布温度数据\n        pub_accel.publish( msg_accel );// 发布加速度消息\n        \n\t// 服务消费者，调用服务，享受服务===\n        if( srv_speed.call( msg_speed ) )// 服务数据中携带，服务反馈值\n        {\n\t    // 日志消息打印，服务数据反馈值========================\n            ROS_INFO_STREAM(\n                        \"SetSpeed response:\\n\" \u003c\u003c\n                        \"Previous speed = \" \u003c\u003c msg_speed.response.previous_speed \u003c\u003c \"\\n\" \u003c\u003c\n                        \"Current  speed = \" \u003c\u003c msg_speed.response.current_speed      \u003c\u003c \"\\n\" \u003c\u003c\n                        \"Motor stalled  = \" \u003c\u003c (msg_speed.response.stalled ? \"true\" : \"false\" )\n                        );\n        }\n        else\n        {\n            /* Note that this might happen at the beginning, because\n               the service server could have not started yet! */\n\t    // 暂时无服务，获取服务提供错误\n            ROS_ERROR_STREAM( \"Call to speed service failed!\" );\n        }\n\n        ++i;\n\n        ros::spinOnce();\n        rate.sleep();\n    }\n\n    return EXIT_SUCCESS;\n\n}\n\n```\n\n\n## 5. 自定义服务消息 服务端 + 日志打印 上街叫卖.jpg\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cros/console.h\u003e\n\n#include \u003cstd_msgs/Int32.h\u003e\n#include \u003cgeometry_msgs/Vector3.h\u003e\n\n#include \u003cchapter4_tutorials/SetSpeed.h\u003e\n\n// 全局变量，记录前后两次的速度=====\nfloat previous_speed = 0.;\nfloat current_speed  = 0.;\n\n// 订阅 温度数据话题，回调函数\nvoid callback_temperature( const std_msgs::Int32::ConstPtr\u0026 msg )\n{\n    // 日志打印收到的消息\n    ROS_INFO_STREAM( \"Temperature = \" \u003c\u003c msg-\u003edata );\n}\n\n// 订阅加速度数据话题，回调函数\nvoid callback_acceleration( const geometry_msgs::Vector3::ConstPtr\u0026 msg )\n{\n    // 日志打印收到的消息\n    ROS_INFO_STREAM(\"Acceleration = (\" \u003c\u003c msg-\u003ex \u003c\u003c \", \" \u003c\u003c msg-\u003ey \u003c\u003c \", \" \u003c\u003c msg-\u003ez \u003c\u003c \")\");\n}\n// 话题数据======是生产者主导==============被动消费=====容易爆仓========生产导向=================\n\n// 服务话题回调函数=====消费者主导==========主动消费=====主动权在手=====顾客是上帝=====需求导向====\nbool callback_speed(chapter4_tutorials::SetSpeed::Request  \u0026req, // 服务请求，消费者主动发来的\n                    chapter4_tutorials::SetSpeed::Response \u0026res) // 服务反馈，提供者，完成服务后的反馈信息\n{\n    // 打印 服务客户端发来的 服务请求，服务要求，期望速度\n    ROS_INFO_STREAM(\"Speed service request: desired speed = \" \u003c\u003c req.desired_speed);\n\n    current_speed = 0.9 * req.desired_speed;// 当前速度，仿真\n\n    res.previous_speed = previous_speed;\n    res.current_speed  = current_speed;\n    res.stalled        = current_speed \u003c 0.1;\n\n    previous_speed = current_speed;// 迭代======\n\n    return true;\n}\n\n\nint main( int argc, char **argv )\n{\n\n    ros::init( argc, argv, \"program5\" );\n\n    ros::NodeHandle nh;\n\n    // 订阅话题，直接购买商品，有多少我要多少=====土豪脸.jpg\n    // 温度数据 话题\n    ros::Subscriber sub_temp = nh.subscribe( \"temperature\", 1000, callback_temperature);\n    // 加速度数据话题\n    ros::Subscriber sub_accel = nh.subscribe( \"acceleration\", 1000, callback_acceleration);\n    \n    // 发布服务，广播消息，打广告，请把需求砸过来!!!!!!!    可爱脸.jpg \n    ros::ServiceServer srv_speed = nh.advertiseService( \"speed\", callback_speed );\n\n    ros::spin();\n    \n    return EXIT_SUCCESS;\n}\n\n```\n\n\n## 6. 动态参数配置 + 日志\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cdynamic_reconfigure/server.h\u003e\n\n#include \u003cchapter4_tutorials/DynamicParamConfig.h\u003e// 自定义 参数\n// cfg/DynamicParam.cfg-----------------------\n/*\n# coding: utf-8\n#!/usr/bin/env python\n\nPACKAGE='chapter4_tutorials' # 包名\n\nfrom math import pi\nfrom dynamic_reconfigure.parameter_generator_catkin import *\nfrom dynamic_reconfigure.msg import SensorLevels\n\ngen = ParameterGenerator() # 参数生成\n\ngen.add('BOOL', bool_t, SensorLevels.RECONFIGURE_RUNNING,\n        'Bool param', True)\ngen.add('INT', int_t, SensorLevels.RECONFIGURE_STOP,\n        'Int param', 0, -10, 10)\ngen.add('DOUBLE', double_t, SensorLevels.RECONFIGURE_CLOSE,\n        'Double param', 0.0, -pi, pi)\n# 常量\nfoo = gen.const('ros', str_t,  'Ros',   'ROS')\nbar = gen.const('cook', str_t, 'Cook', 'COOK')\nbaz = gen.const('book', str_t, 'Book', 'BOOK')\n# 枚举变量\nstrings = gen.enum([foo, bar, baz], 'Strings')\n# 添加自定义的枚举变量\ngen.add('STRING', str_t, SensorLevels.RECONFIGURE_RUNNING,\n        'String param', 'Ros', edit_method = strings)\n\t\n# 生成消息 头文件\nexit(gen.generate(PACKAGE, PACKAGE, 'DynamicParam'))\n*/ \n// ------------------------------------\n\n// 动态参数服务器\nclass DynamicParamServer\n{\npublic:\n    DynamicParamServer()\n    {\n    // 动态参数配置服务器设置，参数改变后响应的 回调函数\n        _cfg_server.setCallback(boost::bind(\u0026DynamicParamServer::callback, this, _1, _2));\n    }\n\n    void callback(chapter4_tutorials::DynamicParamConfig\u0026 config, uint32_t level)\n    {\n    // 打印动态配置后的参数\n        ROS_INFO_STREAM(\n                    \"New configuration received with level = \" \u003c\u003c level \u003c\u003c \":\\n\" \u003c\u003c\n                    \"BOOL   = \" \u003c\u003c config.BOOL \u003c\u003c \"\\n\" \u003c\u003c\n                    \"INT    = \" \u003c\u003c config.INT\u003c\u003c \"\\n\" \u003c\u003c\n                    \"DOUBLE = \" \u003c\u003c config.DOUBLE \u003c\u003c \"\\n\" \u003c\u003c\n                    \"STRING = \" \u003c\u003c config.STRING\n                    );\n    }\n\nprivate:\n    // 接收 参数类型后实例化的 动态参数配置服务器对象\n    dynamic_reconfigure::Server\u003cchapter4_tutorials::DynamicParamConfig\u003e _cfg_server;\n};\n\nint main(int argc, char** argv)\n{\n    ros::init(argc, argv, \"program6\");\n\n    DynamicParamServer dps;// 定义参数服务器类，修改参数后，回调函数会指定执行\n\n    while(ros::ok())\n    {\n        ros::spin();\n    }\n\n    return EXIT_SUCCESS;\n}\n\n```\n\n\n## 7. diagnostic_updater 诊断\n[ diagnostic_updater/diagnostic_updater.h 诊断???](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter04/chapter4_tutorials/src/program7.cpp)\n\n\n## 8. 发布图像消息 + 日志\n```c\n#include \u003cros/ros.h\u003e\n\n#include \u003cimage_transport/image_transport.h\u003e // 图像发送\n#include \u003ccv_bridge/cv_bridge.h\u003e// opencv 图像 转换成 ros图像\n#include \u003csensor_msgs/image_encodings.h\u003e // 图像编码\n\n#include \u003copencv2/highgui/highgui.hpp\u003e// opencvgui\n\nint main( int argc, char **argv )\n{\n    ros::init( argc, argv, \"program8\" );\n\n    ros::NodeHandle nh;\n\n    /*Open camera with CAMERA_INDEX (webcam is typically #0).*/\n    const int CAMERA_INDEX = 0; // 摄像头id\n    cv::VideoCapture capture( CAMERA_INDEX );// opencv打开相机\n\n    if(not capture.isOpened() )\n    {// 打开相机发生错误\n        ROS_ERROR_STREAM(\"Failed to open camera with index \" \u003c\u003c CAMERA_INDEX \u003c\u003c \"!\");\n        ros::shutdown();\n    }\n    \n    // 图像信息发送器\n    image_transport::ImageTransport it(nh);\n    // 发布图像消息\n    image_transport::Publisher pub_image = it.advertise( \"camera\", 1 );\n    \n    // opencv 图像 带 时间戳\n    cv_bridge::CvImagePtr frame = boost::make_shared\u003c cv_bridge::CvImage \u003e();\n    frame-\u003eencoding = sensor_msgs::image_encodings::BGR8;\n\n    while( ros::ok() ) {\n        capture \u003e\u003e frame-\u003eimage;// 图像域\n\n        if( frame-\u003eimage.empty() )\n        {\n            ROS_ERROR_STREAM( \"Failed to capture frame!\" );\n            ros::shutdown();\n        }\n\n        frame-\u003eheader.stamp = ros::Time::now();// 时间戳\n        pub_image.publish( frame-\u003etoImageMsg() );// 转换成 ros图像消息后发布出去====\n\n        cv::waitKey( 3 );\n\n        ros::spinOnce();\n    }\n\n    capture.release();// 释放相机=======\n\n    return EXIT_SUCCESS;\n}\n\n```\n\n\n## 9. 发布点云消息 + 日志 \n```c\n#include \u003cros/ros.h\u003e\n\n#include \u003cvisualization_msgs/Marker.h\u003e       // rviz可视化图像/marker\n\n#include \u003csensor_msgs/PointCloud2.h\u003e         // 点云消息\n#include \u003cpcl_conversions/pcl_conversions.h\u003e // pcl类型转换成 rospcl类型\n#include \u003cpcl/point_cloud.h\u003e// 点云\n#include \u003cpcl/point_types.h\u003e// 点类型\n\nint main( int argc, char **argv )\n{\n  ros::init( argc, argv, \"program9\" );\n\n  ros::NodeHandle n;\n\n  // 发布marker消息\n  ros::Publisher pub_marker = n.advertise\u003c visualization_msgs::Marker \u003e( \"marker\", 1000 );\n  // 发布点云消息\n  ros::Publisher pub_pc = n.advertise\u003c sensor_msgs::PointCloud2 \u003e( \"pc\", 1000 );\n  \n  // 可视化marker消息----------------------------------------------------\n  visualization_msgs::Marker msg_marker;\n  msg_marker.header.frame_id = \"/frame_world\"; // 消息头，坐标系id\n  msg_marker.ns = \"shapes\"; // 所属命名空间\n  msg_marker.id = 0;        // id\n  msg_marker.type = visualization_msgs::Marker::CUBE;  // 形状类型，正方体\n  msg_marker.action = visualization_msgs::Marker::ADD; // 叠加\n\n  msg_marker.pose.position.x = 0.;// 位置\n  msg_marker.pose.position.y = 1.;\n  msg_marker.pose.position.z = 2.;\n  msg_marker.pose.orientation.x = 0.;// 姿态 四元素类型\n  msg_marker.pose.orientation.y = 0.;\n  msg_marker.pose.orientation.z = 0.;\n  msg_marker.pose.orientation.w = 1.;\n\n  msg_marker.scale.x = 1.;// 尺寸\n  msg_marker.scale.y = 1.;\n  msg_marker.scale.z = 1.;\n\n  msg_marker.color.r = 1.; // 颜色\n  msg_marker.color.g = 0.;\n  msg_marker.color.b = 0.;\n  msg_marker.color.a = 1.; // 透明度，不透明\n\n  msg_marker.lifetime = ros::Duration();// 声生命周期\n\n  ROS_INFO_STREAM( \"Marker Created.\" );\n\n\n// 点云消息--------------------------------------------\n  sensor_msgs::PointCloud2 msg_pc;// rospcl 类型\n  pcl::PointCloud\u003c pcl::PointXYZ \u003e pc;// pcl XYZ类型点云\n\n  pc.width  = 300;\n  pc.height = 200; // 有序点云\n  pc.is_dense = false;// 有nan点\n  pc.points.resize( pc.width * pc.height );\n  // 随机生成假的点云数据\n  for( size_t i = 0; i \u003c pc.height; ++i ) {\n    for( size_t j = 0; j \u003c pc.width; ++j ) {\n      const size_t k = pc.width * i + j;\n      pc.points[k].x = 0.1 * i;\n      pc.points[k].y = 0.2 * j;\n      pc.points[k].z = 1.5;\n    }\n  }\n\n  ROS_INFO_STREAM( \"Point Cloud Created.\" );\n\n  ros::Rate rate( 1 );\n  \n  while( ros::ok() )\n  {\n    msg_marker.header.stamp = ros::Time::now(); // marker时间戳\n    msg_marker.pose.position.x += 0.01; // 位置在移动\n    msg_marker.pose.position.y += 0.02;\n    msg_marker.pose.position.z += 0.03;\n\n    for( size_t i = 0; i \u003c pc.height; ++i ) {\n      for( size_t j = 0; j \u003c pc.width; ++j ) {\n        const size_t k = pc.width * i + j;\n\n        pc.points[k].z -= 0.1; // z方向位置在移动\n      }\n    }\n\n    pcl::toROSMsg( pc, msg_pc );// pcl点云类型 转换成 rospcl类型\n\n    msg_pc.header.stamp = msg_marker.header.stamp;// 时间戳\n    msg_pc.header.frame_id = \"/frame_robot\";// 坐标系\n\n    pub_marker.publish( msg_marker );// 发布marker\n    pub_pc.publish( msg_pc );        // 发布 点云\n\n    ros::spinOnce();\n    rate.sleep();\n  }\n\n  return EXIT_SUCCESS;\n}\n\n```\n\n\n## 10. 交互式marker +日志\n```c\n#include \u003cros/ros.h\u003e\n#include \u003ctf/tf.h\u003e\n\n#include \u003cinteractive_markers/interactive_marker_server.h\u003e // 交互式marker 可以响应鼠标\n\n// 有交互后的回调函数----------------------------------------------------------------------------\nvoid feedback_callback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr \u0026feedback)\n{\n    double roll, pitch, yaw;\n    tf::Quaternion q;\n    tf::quaternionMsgToTF(feedback-\u003epose.orientation, q);// 获取四元素姿态\n    tf::Matrix3x3(q).getRPY(roll, pitch, yaw);// 对应的姿态向量 \n    \n    // 打印marker的位置 和 姿态\n    ROS_INFO_STREAM(\n                feedback-\u003emarker_name \u003c\u003c \"position (x, y, z) = (\" \u003c\u003c\n                feedback-\u003epose.position.x \u003c\u003c \", \" \u003c\u003c\n                feedback-\u003epose.position.y \u003c\u003c \", \" \u003c\u003c\n                feedback-\u003epose.position.z \u003c\u003c \"), orientation (roll, pitch, yaw) = (\" \u003c\u003c\n                roll \u003c\u003c \", \" \u003c\u003c pitch \u003c\u003c \", \" \u003c\u003c yaw \u003c\u003c \")\"\n                );\n}\n\nint main( int argc, char** argv )\n{\n    ros::init(argc, argv, \"program10\");\n    \n    // 交互式marker服务器\n    interactive_markers::InteractiveMarkerServer server(\"marker\");\n\n    visualization_msgs::InteractiveMarker marker;// 交互式marker 类型\n    marker.header.frame_id = \"base_link\";// 头，坐标系\n    marker.name = \"marker\";// 名字\n    marker.description = \"2-DOF Control\";// 自我介绍\n\n    /* Box marker */\n    visualization_msgs::Marker box_marker;\n    box_marker.type = visualization_msgs::Marker::CUBE; // 正方体\n    box_marker.scale.x = 0.5;// 尺寸\n    box_marker.scale.y = 0.5;\n    box_marker.scale.z = 0.5;\n    box_marker.color.r = 0.5;// 颜色\n    box_marker.color.g = 0.5;\n    box_marker.color.b = 0.5;\n    box_marker.color.a = 1.0;\n\n    /* Non-interactive control which contains the box */\n    visualization_msgs::InteractiveMarkerControl box_control;// 交互式marker控制\n    box_control.always_visible = true;// 一直显示\n    box_control.markers.push_back(box_marker);// 设置控制对象\n\n    /* Controls to move the box */\n    visualization_msgs::InteractiveMarkerControl move_x_control, rotate_z_control;\n    move_x_control.name = \"move_x\";\n    move_x_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MOVE_AXIS;// 沿轴方向移动\n\n    rotate_z_control.name = \"rotate_z\";\n    rotate_z_control.orientation.w = 1;\n    rotate_z_control.orientation.y = 1;\n    rotate_z_control.interaction_mode = visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS;// 沿轴方向旋转\n\n// 交互式marker设置可 交互方式\n    marker.controls.push_back(box_control);\n    marker.controls.push_back(move_x_control);\n    marker.controls.push_back(rotate_z_control);\n\n// 交互式marker服务器吗，设置携带交互方式的 交互式marker\n    server.insert(marker, \u0026feedback_callback);\n    server.applyChanges();\n\n    ros::spin();\n}\n\n```\n\nCMakeLists.txt\n```c\n\ncmake_minimum_required(VERSION 2.8.3)\nproject(chapter4_tutorials)\n\nset(ROS_BUILD_TYPE Debug) # 编译模式\n\n# 找到依赖包\nfind_package(catkin REQUIRED\n    COMPONENTS\n      roscpp\n      message_generation\n      std_msgs\n      geometry_msgs\n      sensor_msgs\n      visualization_msgs\n      dynamic_reconfigure\n      diagnostic_updater\n      cv_bridge\n      image_transport\n      pcl_conversions\n      interactive_markers)\n\n# 找依赖库\nfind_package(OpenCV)\nfind_package(PCL REQUIRED)\n\n# 自定义服务类型\nadd_service_files(FILES SetSpeed.srv)\n# 生成服务类型 的 头文件\ngenerate_messages(DEPENDENCIES std_msgs)\n# 生成动态参数配置参数 的头文件\ngenerate_dynamic_reconfigure_options(cfg/DynamicParam.cfg)\n\n# 设置包\ncatkin_package(\n    CATKIN_DEPENDS\n      roscpp\n      message_runtime\n      std_msgs\n      geometry_msgs\n      sensor_msgs\n      visualization_msgs\n      dynamic_reconfigure\n      diagnostic_updater\n      cv_bridge\n      image_transport\n      pcl_conversions\n      interactive_markers)\n# 添加依赖库 \ninclude_directories(\n    ${catkin_INCLUDE_DIRS}\n    ${OpenCV_INCLUDE_DIRS}\n    ${PCL_INCLUDE_DIRS})\n\n# 编译\nadd_executable(program1 src/program1.cpp)\ntarget_link_libraries(program1 ${catkin_LIBRARIES})\n\nadd_executable(program1_dump src/program1_dump.cpp)\ntarget_link_libraries(program1_dump ${catkin_LIBRARIES})\n\nadd_executable(program1_mem src/program1_mem.cpp)\ntarget_link_libraries(program1_mem ${catkin_LIBRARIES})\n\nadd_executable(program2 src/program2.cpp)\ntarget_link_libraries(program2 ${catkin_LIBRARIES})\n\nadd_executable(program3 src/program3.cpp)\ntarget_link_libraries(program3 ${catkin_LIBRARIES})\n\nadd_executable(program4 src/program4.cpp)\nadd_dependencies(program4 ${PROJECT_NAME}_generate_messages_cpp)\ntarget_link_libraries(program4 ${catkin_LIBRARIES})\n\nadd_executable(program5 src/program5.cpp)\nadd_dependencies(program5 ${PROJECT_NAME}_generate_messages_cpp)\ntarget_link_libraries(program5 ${catkin_LIBRARIES})\n\nadd_executable(program6 src/program6.cpp)\nadd_dependencies(program6 ${PROJECT_NAME}_gencfg)\ntarget_link_libraries(program6 ${catkin_LIBRARIES})\n\nadd_executable(program7 src/program7.cpp)\ntarget_link_libraries(program7 ${catkin_LIBRARIES})\n\nadd_executable(program8 src/program8.cpp)\ntarget_link_libraries(program8 ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})\n\nadd_executable(program9 src/program9.cpp)\ntarget_link_libraries(program9 ${catkin_LIBRARIES} ${PCL_LIBRARIES})\n\nadd_executable(program10 src/program10.cpp)\ntarget_link_libraries(program10 ${catkin_LIBRARIES})\n\n```\n\n\n# 四、发布 雷达数据 坐标变换 里程计数据\n\n## 1. 发布雷达数据\n```c\n#include \u003cros/ros.h\u003e\n#include \u003csensor_msgs/LaserScan.h\u003e // 雷达扫描数据\n\nint main(int argc, char** argv)\n{\n ros::init(argc, argv, \"laser_scan_publisher\");\n ros::NodeHandle n;\n \n // 话题 发布 雷达扫描数据\n ros::Publisher scan_pub = n.advertise\u003csensor_msgs::LaserScan\u003e(\"scan\", 50);\n\n unsigned int num_readings = 100;  // 一周数据点??\n double laser_frequency = 40;      // 频率\n double ranges[num_readings];      // 范围\n double intensities[num_readings]; // 密度\n int count = 0;\n\n\n ros::Rate r(1.0);\n\n while(n.ok()){\n\n    // 生成假的雷达数据=============\n    for(unsigned int i = 0; i \u003c num_readings; ++i)\n    {\n     ranges[i] = count;            // 距离数据\n     intensities[i] = 100 + count; // 密度数据，反射强度??\n    }\n    \n    \n    // 准备雷达数据=========================\n    ros::Time scan_time = ros::Time::now();\n    sensor_msgs::LaserScan scan;// 定义雷达数据\n    scan.header.stamp = scan_time;// 时间戳\n    scan.header.frame_id = \"base_link\";// 坐标系\n    scan.angle_min = -1.57; // 扫描最小角度 -90度\n    scan.angle_max = 1.57;  // 扫描最大角度 +90度\n    scan.angle_increment = 3.14 / num_readings; // 180度 100个数据，角度分辨率\n    scan.time_increment = (1 / laser_frequency) / (num_readings);// 每一个扫描需要的时间，时间增量\n    scan.range_min = 0.0;    // 数据范围\n    scan.range_max = 100.0;\n    scan.ranges.resize(num_readings); // 距离范围数据\n    scan.intensities.resize(num_readings);// 强度数据??\n\n    for(unsigned int i = 0; i \u003c num_readings; ++i)\n    {\n     // 填充距离数据 和 强度数据\n     scan.ranges[i] = ranges[i];\n     scan.intensities[i] = intensities[i];\n    }\n    \n    // 发布雷达数据\n    scan_pub.publish(scan);\n    ++count;\n    r.sleep();\n\n }\n\n}\n\n\n```\n\n## 2. 发布里程计数据\n```c\n#include \u003cstring\u003e\n#include \u003cros/ros.h\u003e\n#include \u003csensor_msgs/JointState.h\u003e   // 关节状态??\n#include \u003ctf/transform_broadcaster.h\u003e // 左边变换 广播\n#include \u003cnav_msgs/Odometry.h\u003e        // 导航下的里程计消息\n\n\nint main(int argc, char** argv)\n{\n\tros::init(argc, argv, \"state_publisher\");\n\tros::NodeHandle n;\n\t\n\t// 发布里程计消息\n\tros::Publisher odom_pub = n.advertise\u003cnav_msgs::Odometry\u003e(\"odom\", 10);\n\n\t// 初始2d位姿\n\tdouble x = 0.0; \n\tdouble y = 0.0;\n\tdouble th = 0;\n\n\t// 速度 velocity\n\tdouble vx = 0.4; // 前进线速度\n\tdouble vy = 0.0;\n\tdouble vth = 0.4;// 旋转角速度\n\n\tros::Time current_time;\n\tros::Time last_time;\n\tcurrent_time = ros::Time::now();// 当前时间\n\tlast_time = ros::Time::now();   // 上次时间\n\n\ttf::TransformBroadcaster broadcaster; // 位姿 广播\n\tros::Rate loop_rate(20);// 频率\n\n\tconst double degree = M_PI/180; // 度转 弧度\n\n\t// message declarations\n\tgeometry_msgs::TransformStamped odom_trans; // 坐标变换消息\n\todom_trans.header.frame_id = \"odom\";\n\todom_trans.child_frame_id = \"base_footprint\";\n\n\twhile (ros::ok()) {\n\t\tcurrent_time = ros::Time::now(); // 当前时间\n\n\t\tdouble dt = (current_time - last_time).toSec();// 两次时间差\n\t\tdouble delta_x = (vx * cos(th) - vy * sin(th)) * dt;\n\t\tdouble delta_y = (vx * sin(th) + vy * cos(th)) * dt;\n\t\tdouble delta_th = vth * dt;\n\t\t\n\t\t//     \\vy y  /vx\n\t\t//      \\  | /\n\t\t//       \\ |/\n\t\t//        -------x-------\n\t\t//\n\n\t\tx += delta_x;\n\t\ty += delta_y;\n\t\tth += delta_th;\n\n\t\tgeometry_msgs::Quaternion odom_quat;// 四元素位姿\t\n\t\todom_quat = tf::createQuaternionMsgFromRollPitchYaw(0,0,th);// rpy转换到 四元素\n\n\t\t// 更新左边变换消息，tf广播发布==================\n\t\todom_trans.header.stamp = current_time; // 当前时间\n\t\todom_trans.transform.translation.x = x; // 位置 \n\t\todom_trans.transform.translation.y = y; \n\t\todom_trans.transform.translation.z = 0.0;\n\t\todom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(th);// 位姿\n\n\t\t// 更新 里程计消息\n\t\tnav_msgs::Odometry odom;//  里程计消息\n\t\todom.header.stamp = current_time;// 当前时间\n\t\todom.header.frame_id = \"odom\";\n\t\todom.child_frame_id = \"base_footprint\";\n\n\t\t// 位置 position\n\t\todom.pose.pose.position.x = x;\n\t\todom.pose.pose.position.y = y;\n\t\todom.pose.pose.position.z = 0.0;\n\t\todom.pose.pose.orientation = odom_quat; // 位姿\n\n\t\t// 速度 velocity\n\t\todom.twist.twist.linear.x = vx;// 线速度\n\t\todom.twist.twist.linear.y = vy;\n\t\todom.twist.twist.linear.z = 0.0;\n\t\todom.twist.twist.angular.x = 0.0; // 小速度\n\t\todom.twist.twist.angular.y = 0.0;\n\t\todom.twist.twist.angular.z = vth;\n\n\t\tlast_time = current_time;// 迭代消息\n\n\t\t// publishing the odometry and the new tf\n\t\tbroadcaster.sendTransform(odom_trans);// 发布坐标变换消息 =====\n\t\todom_pub.publish(odom);// 发布里程计消息====\n\n\t\tloop_rate.sleep();\n\t}\n\treturn 0;\n}\n\n```\n\n## 3. 发布 目标位置 action\n```c\n#include \u003cros/ros.h\u003e\n#include \u003cmove_base_msgs/MoveBaseAction.h\u003e // 移动底盘 action消息\n#include \u003cactionlib/client/simple_action_client.h\u003e// action 客户端，发布目标\n#include \u003ctf/transform_broadcaster.h\u003e// 坐标变换广播\n#include \u003csstream\u003e\n\n// action 客户端==========\ntypedef actionlib::SimpleActionClient\u003cmove_base_msgs::MoveBaseAction\u003e MoveBaseClient;\n\nint main(int argc, char** argv)\n{\n\tros::init(argc, argv, \"navigation_goals\");\n\t\n        // action 客户端\n\tMoveBaseClient ac(\"move_base\", true);\n        \n\t// 等待action服务 启动\n\twhile(!ac.waitForServer(ros::Duration(5.0)))\n\t{\n\t\tROS_INFO(\"Waiting for the move_base action server\");\n\t}\n        \n\t// action 目标信息 目标位置\n\tmove_base_msgs::MoveBaseGoal goal;\n\n\tgoal.target_pose.header.frame_id = \"map\";// 坐标系\n\tgoal.target_pose.header.stamp = ros::Time::now();// 时间戳\n\n\tgoal.target_pose.pose.position.x = 1.0;// 目标位置\n\tgoal.target_pose.pose.position.y = 1.0;\n\tgoal.target_pose.pose.orientation.w = 1.0;// 姿态\n\n\tROS_INFO(\"Sending goal\");\n\tac.sendGoal(goal);// 发送 action 目标\n\n\tac.waitForResult(); // 等待 action服务端 完成action\n\n\tif(ac.getState() == actionlib::SimpleClientGoalState::SUCCEEDED)\n\t\tROS_INFO(\"You have arrived to the goal position\");\n\telse{\n\t\tROS_INFO(\"The base failed for some reason\");\n\t}\n\treturn 0;\n}\n\n```\n\n# 五、综合 应用\n\n## 1. 三维重建 opencv pcl g2o \n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter08/chapter8_tutorials/opencv_candidate/src/reconst3d/reconstruction.cpp)\n\n\n## 2. RGBD数据处理\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter08/chapter8_tutorials/opencv_candidate/src/rgbd/src/odometry.cpp)\n\n\n\n## 3. 机器人控制  pid 笛卡尔臂控制 差分底盘控制\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter08/chapter8_tutorials/robot_controllers/robot_controllers/src/pid.cpp)\n\n\n\n## 4. 智能抓取\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/blob/master/Chapter08/chapter8_tutorials/smart_grasping_sandbox/smart_grasping_sandbox/src/smart_grasping_sandbox/smart_grasper.py)\n\n\n## 5. universal_robot  UR机械臂 UR3 UR5 UR10 MOVI配置 gazebo 运动学\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/tree/master/Chapter08/chapter8_tutorials/universal_robot)\n\n\n## 6. 发布自定义消息 msg\n[multi sensor fusion EKF多传感器融合框架 ](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/tree/master/Chapter09/chapter9_tutorials/ethzasl_msf)\n\n\n## 7. 地理信息系统\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/tree/master/Chapter09/chapter9_tutorials/geographic_info)\n\n\n## 8. 无人机仿真\n[参考](https://github.com/PacktPublishing/Robot-Operating-System-Cookbook/tree/master/Chapter09/chapter9_tutorials/rotors_simulator)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEwenwan%2FRos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEwenwan%2FRos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEwenwan%2FRos/lists"}