动作是ROS中的一种异步通信形式,动作客户端向动作服务器发送目标请求,目标服务器向操作客户端发送目标反馈和结果。本文基于前一篇自定义动作博文。

1.创建一个action_turtorials_cpp

1.1 创建一个action_turtorials_cpp

在终端运行:

  1. cd ~/action_ws/src
  2. ros2 pkg create --dependencies action_tutorials_interfaces rclcpp rclcpp_action rclcpp_components -- action_tutorials_cpp

1.2添加可见性控件

为了使包可以在Windows上编译和工作,我们需要添加一些“可见性控制”。有关为什么需要这样做的详细信息,请参见这里

打开action_tutorials_cpp/include/action_tutorials_cpp/ visbility_control .h,并放入以下代码:

  1. #ifndef ACTION_TUTORIALS_CPP__VISIBILITY_CONTROL_H_
  2. #define ACTION_TUTORIALS_CPP__VISIBILITY_CONTROL_H_
  3. #ifdef __cplusplus
  4. extern "C"
  5. {
  6. #endif
  7. // This logic was borrowed (then namespaced) from the examples on the gcc wiki:
  8. // https://gcc.gnu.org/wiki/Visibility
  9. #if defined _WIN32 || defined __CYGWIN__
  10. #ifdef __GNUC__
  11. #define ACTION_TUTORIALS_CPP_EXPORT __attribute__ ((dllexport))
  12. #define ACTION_TUTORIALS_CPP_IMPORT __attribute__ ((dllimport))
  13. #else
  14. #define ACTION_TUTORIALS_CPP_EXPORT __declspec(dllexport)
  15. #define ACTION_TUTORIALS_CPP_IMPORT __declspec(dllimport)
  16. #endif
  17. #ifdef ACTION_TUTORIALS_CPP_BUILDING_DLL
  18. #define ACTION_TUTORIALS_CPP_PUBLIC ACTION_TUTORIALS_CPP_EXPORT
  19. #else
  20. #define ACTION_TUTORIALS_CPP_PUBLIC ACTION_TUTORIALS_CPP_IMPORT
  21. #endif
  22. #define ACTION_TUTORIALS_CPP_PUBLIC_TYPE ACTION_TUTORIALS_CPP_PUBLIC
  23. #define ACTION_TUTORIALS_CPP_LOCAL
  24. #else
  25. #define ACTION_TUTORIALS_CPP_EXPORT __attribute__ ((visibility("default")))
  26. #define ACTION_TUTORIALS_CPP_IMPORT
  27. #if __GNUC__ >= 4
  28. #define ACTION_TUTORIALS_CPP_PUBLIC __attribute__ ((visibility("default")))
  29. #define ACTION_TUTORIALS_CPP_LOCAL __attribute__ ((visibility("hidden")))
  30. #else
  31. #define ACTION_TUTORIALS_CPP_PUBLIC
  32. #define ACTION_TUTORIALS_CPP_LOCAL
  33. #endif
  34. #define ACTION_TUTORIALS_CPP_PUBLIC_TYPE
  35. #endif
  36. #ifdef __cplusplus
  37. }
  38. #endif
  39. #endif // ACTION_TUTORIALS_CPP__VISIBILITY_CONTROL_H_

2.编写一个动作服务器

接下来编写一个动作服务器,使用在前文创建的动作接口来计算斐波那契数列。

2.1编写动作服务器

打开action_tutorials_cpp/src/fibonacci_action_server.cpp(需要自己创建),输入以下代码:

  1. #include <functional>
  2. #include <memory>
  3. #include <thread>
  4. #include "action_tutorials_interfaces/action/fibonacci.hpp"
  5. #include "rclcpp/rclcpp.hpp"
  6. #include "rclcpp_action/rclcpp_action.hpp"
  7. #include "rclcpp_components/register_node_macro.hpp"
  8. #include "action_tutorials_cpp/visibility_control.h"
  9. namespace action_tutorials_cpp
  10. {
  11. class FibonacciActionServer : public rclcpp::Node
  12. {
  13. public:
  14. using Fibonacci = action_tutorials_interfaces::action::Fibonacci;
  15. using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;
  16. ACTION_TUTORIALS_CPP_PUBLIC
  17. explicit FibonacciActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
  18. : Node("fibonacci_action_server", options)
  19. {
  20. using namespace std::placeholders;
  21. this->action_server_ = rclcpp_action::create_server<Fibonacci>(
  22. this,
  23. "fibonacci",
  24. std::bind(&FibonacciActionServer::handle_goal, this, _1, _2),
  25. std::bind(&FibonacciActionServer::handle_cancel, this, _1),
  26. std::bind(&FibonacciActionServer::handle_accepted, this, _1));
  27. }
  28. private:
  29. rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;
  30. rclcpp_action::GoalResponse handle_goal(
  31. const rclcpp_action::GoalUUID & uuid,
  32. std::shared_ptr<const Fibonacci::Goal> goal)
  33. {
  34. RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order);
  35. (void)uuid;
  36. return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  37. }
  38. rclcpp_action::CancelResponse handle_cancel(
  39. const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  40. {
  41. RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
  42. (void)goal_handle;
  43. return rclcpp_action::CancelResponse::ACCEPT;
  44. }
  45. void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  46. {
  47. using namespace std::placeholders;
  48. // this needs to return quickly to avoid blocking the executor, so spin up a new thread
  49. std::thread{std::bind(&FibonacciActionServer::execute, this, _1), goal_handle}.detach();
  50. }
  51. void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  52. {
  53. RCLCPP_INFO(this->get_logger(), "Executing goal");
  54. rclcpp::Rate loop_rate(1);
  55. const auto goal = goal_handle->get_goal();
  56. auto feedback = std::make_shared<Fibonacci::Feedback>();
  57. auto & sequence = feedback->partial_sequence;
  58. sequence.push_back(0);
  59. sequence.push_back(1);
  60. auto result = std::make_shared<Fibonacci::Result>();
  61. for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i) {
  62. // Check if there is a cancel request
  63. if (goal_handle->is_canceling()) {
  64. result->sequence = sequence;
  65. goal_handle->canceled(result);
  66. RCLCPP_INFO(this->get_logger(), "Goal canceled");
  67. return;
  68. }
  69. // Update sequence
  70. sequence.push_back(sequence[i] + sequence[i - 1]);
  71. // Publish feedback
  72. goal_handle->publish_feedback(feedback);
  73. RCLCPP_INFO(this->get_logger(), "Publish feedback");
  74. loop_rate.sleep();
  75. }
  76. // Check if goal is done
  77. if (rclcpp::ok()) {
  78. result->sequence = sequence;
  79. goal_handle->succeed(result);
  80. RCLCPP_INFO(this->get_logger(), "Goal succeeded");
  81. }
  82. }
  83. }; // class FibonacciActionServer
  84. } // namespace action_tutorials_cpp
  85. RCLCPP_COMPONENTS_REGISTER_NODE(action_tutorials_cpp::FibonacciActionServer)

前几行包含需要编译的所有头文件。

接下来,创建一个rclcpp::Node的派生类:

  1. class FibonacciActionServer : public rclcpp::Node

FibonacciActionServer类的构造函数初始化fibonacci_action_server节点:

  1. explicit FibonacciActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
  2. : Node("fibonacci_action_server", options)

构造函数还实例化了一个新的动作服务器:

  1. this->action_server_ = rclcpp_action::create_server<Fibonacci>(
  2. this,
  3. "fibonacci",
  4. std::bind(&FibonacciActionServer::handle_goal, this, _1, _2),
  5. std::bind(&FibonacciActionServer::handle_cancel, this, _1),
  6. std::bind(&FibonacciActionServer::handle_accepted, this, _1));

这个动作服务有6样东西:

  1. 模板化的动作类型名称:Fibonacci
  2. 将一个ROS2节点的动作添加到:this。
  3. 动作名称:fibonacci
  4. 处理目标的回调函数:handle_goal
  5. 处理取消的回调函数:handle_cancel
  6. 处理目标接收的函数:handle_accept

该文件的下一个内容是各种回调的实现。请注意,所有的回调都需要快速返回,否则就会有耗尽执行程序的风险。

处理新的目标的回调函数:

  1. rclcpp_action::GoalResponse handle_goal(
  2. const rclcpp_action::GoalUUID & uuid,
  3. std::shared_ptr<const Fibonacci::Goal> goal)
  4. {
  5. RCLCPP_INFO(this->get_logger(), "Received goal request with order %d", goal->order);
  6. (void)uuid;
  7. return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  8. }

这个实现仅仅接收目标。

处理取消的回调函数:

  1. rclcpp_action::CancelResponse handle_cancel(
  2. const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  3. {
  4. RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
  5. (void)goal_handle;
  6. return rclcpp_action::CancelResponse::ACCEPT;
  7. }

这个实现只是告诉客户机它接受了取消。

最后一个回调函数接受一个新目标并开始处理它:

  1. void handle_accepted(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  2. {
  3. using namespace std::placeholders;
  4. // this needs to return quickly to avoid blocking the executor, so spin up a new thread
  5. std::thread{std::bind(&FibonacciActionServer::execute, this, _1), goal_handle}.detach();
  6. }

由于执行是一个长期运行的操作,所以派生出一个线程来执行实际工作,并从handle_accepted快速返回。

所有进一步的处理和更新都在新线程的execute方法中完成:

  1. void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)
  2. {
  3. RCLCPP_INFO(this->get_logger(), "Executing goal");
  4. rclcpp::Rate loop_rate(1);
  5. const auto goal = goal_handle->get_goal();
  6. auto feedback = std::make_shared<Fibonacci::Feedback>();
  7. auto & sequence = feedback->partial_sequence;
  8. sequence.push_back(0);
  9. sequence.push_back(1);
  10. auto result = std::make_shared<Fibonacci::Result>();
  11. for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i) {
  12. // Check if there is a cancel request
  13. if (goal_handle->is_canceling()) {
  14. result->sequence = sequence;
  15. goal_handle->canceled(result);
  16. RCLCPP_INFO(this->get_logger(), "Goal canceled");
  17. return;
  18. }
  19. // Update sequence
  20. sequence.push_back(sequence[i] + sequence[i - 1]);
  21. // Publish feedback
  22. goal_handle->publish_feedback(feedback);
  23. RCLCPP_INFO(this->get_logger(), "Publish feedback");
  24. loop_rate.sleep();
  25. }
  26. // Check if goal is done
  27. if (rclcpp::ok()) {
  28. result->sequence = sequence;
  29. goal_handle->succeed(result);
  30. RCLCPP_INFO(this->get_logger(), "Goal succeeded");
  31. }
  32. }

这个工作线程每秒处理一个斐波那契数列序号,为每个步骤发布一个反馈更新。当它完成处理时,它将goal_handle标记为成功,然后退出。

2.2编译动作服务器

设置CMakeLists.txt,以便编译动作服务器。打开action_tutorials_cpp/CMakeLists.txt,并在find_package调用之后添加以下内容:

  1. add_library(action_server SHARED
  2. src/fibonacci_action_server.cpp)
  3. target_include_directories(action_server PRIVATE
  4. $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  5. $<INSTALL_INTERFACE:include>)
  6. target_compile_definitions(action_server
  7. PRIVATE "ACTION_TUTORIALS_CPP_BUILDING_DLL")
  8. ament_target_dependencies(action_server
  9. "action_tutorials_interfaces"
  10. "rclcpp"
  11. "rclcpp_action"
  12. "rclcpp_components")
  13. rclcpp_components_register_node(action_server PLUGIN "action_tutorials_cpp::FibonacciActionServer" EXECUTABLE fibonacci_action_server)
  14. install(TARGETS
  15. action_server
  16. ARCHIVE DESTINATION lib
  17. LIBRARY DESTINATION lib
  18. RUNTIME DESTINATION bin)

现在可以编译包了,进入action_ws的根目录,并运行:

  1. colcon build

2.3运行动作服务器

现在已经构建了动作服务器,可以运行它:

  1. ros2 run action_tutorials_cpp fibonacci_action_server

3.编写动作客服端

3.1编写动作客户节点代码

打开action_tutorials_cpp/src/fibonacci_action_client.cpp(需要创建),加入以下代码:

  1. #include <functional>
  2. #include <future>
  3. #include <memory>
  4. #include <string>
  5. #include <sstream>
  6. #include "action_tutorials_interfaces/action/fibonacci.hpp"
  7. #include "rclcpp/rclcpp.hpp"
  8. #include "rclcpp_action/rclcpp_action.hpp"
  9. #include "rclcpp_components/register_node_macro.hpp"
  10. namespace action_tutorials_cpp
  11. {
  12. class FibonacciActionClient : public rclcpp::Node
  13. {
  14. public:
  15. using Fibonacci = action_tutorials_interfaces::action::Fibonacci;
  16. using GoalHandleFibonacci = rclcpp_action::ClientGoalHandle<Fibonacci>;
  17. explicit FibonacciActionClient(const rclcpp::NodeOptions & options)
  18. : Node("fibonacci_action_client", options)
  19. {
  20. this->client_ptr_ = rclcpp_action::create_client<Fibonacci>(
  21. this,
  22. "fibonacci");
  23. this->timer_ = this->create_wall_timer(
  24. std::chrono::milliseconds(500),
  25. std::bind(&FibonacciActionClient::send_goal, this));
  26. }
  27. void send_goal()
  28. {
  29. using namespace std::placeholders;
  30. this->timer_->cancel();
  31. if (!this->client_ptr_->wait_for_action_server()) {
  32. RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
  33. rclcpp::shutdown();
  34. }
  35. auto goal_msg = Fibonacci::Goal();
  36. goal_msg.order = 10;
  37. RCLCPP_INFO(this->get_logger(), "Sending goal");
  38. auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions();
  39. send_goal_options.goal_response_callback =
  40. std::bind(&FibonacciActionClient::goal_response_callback, this, _1);
  41. send_goal_options.feedback_callback =
  42. std::bind(&FibonacciActionClient::feedback_callback, this, _1, _2);
  43. send_goal_options.result_callback =
  44. std::bind(&FibonacciActionClient::result_callback, this, _1);
  45. this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
  46. }
  47. private:
  48. rclcpp_action::Client<Fibonacci>::SharedPtr client_ptr_;
  49. rclcpp::TimerBase::SharedPtr timer_;
  50. void goal_response_callback(std::shared_future<GoalHandleFibonacci::SharedPtr> future)
  51. {
  52. auto goal_handle = future.get();
  53. if (!goal_handle) {
  54. RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
  55. } else {
  56. RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
  57. }
  58. }
  59. void feedback_callback(
  60. GoalHandleFibonacci::SharedPtr,
  61. const std::shared_ptr<const Fibonacci::Feedback> feedback)
  62. {
  63. std::stringstream ss;
  64. ss << "Next number in sequence received: ";
  65. for (auto number : feedback->partial_sequence) {
  66. ss << number << " ";
  67. }
  68. RCLCPP_INFO(this->get_logger(), ss.str().c_str());
  69. }
  70. void result_callback(const GoalHandleFibonacci::WrappedResult & result)
  71. {
  72. switch (result.code) {
  73. case rclcpp_action::ResultCode::SUCCEEDED:
  74. break;
  75. case rclcpp_action::ResultCode::ABORTED:
  76. RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
  77. return;
  78. case rclcpp_action::ResultCode::CANCELED:
  79. RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
  80. return;
  81. default:
  82. RCLCPP_ERROR(this->get_logger(), "Unknown result code");
  83. return;
  84. }
  85. std::stringstream ss;
  86. ss << "Result received: ";
  87. for (auto number : result.result->sequence) {
  88. ss << number << " ";
  89. }
  90. RCLCPP_INFO(this->get_logger(), ss.str().c_str());
  91. rclcpp::shutdown();
  92. }
  93. }; // class FibonacciActionClient
  94. } // namespace action_tutorials_cpp
  95. RCLCPP_COMPONENTS_REGISTER_NODE(action_tutorials_cpp::FibonacciActionClient)

前几行包含需要编译的所有头文件。

接下来,创建一个rclcpp::Node的派生类:

  1. class FibonacciActionClient : public rclcpp::Node

FibonacciActionClient类的构造函数初始化节点fibonacci_action_client

  1. explicit FibonacciActionClient(const rclcpp::NodeOptions & options)
  2. : Node("fibonacci_action_client", options)

构造函数还实例化了一个新的动作客户端:

  1. this->client_ptr_ = rclcpp_action::create_client<Fibonacci>(
  2. this,
  3. "fibonacci");

一个动作客户端需要3件东西:

  1. 动作类型名称:Fibonacci

  2. 将动作客户端添加到的ROS2节点:this

  3. 动作名:fibonacci

实例化一个ROS定时器,它将启动对send_goal的唯一调用:

  1. this->timer_ = this->create_wall_timer(
  2. std::chrono::milliseconds(500),
  3. std::bind(&FibonacciActionClient::send_goal, this));

当计时器到期时,它将调用send_goal:

  1. void send_goal()
  2. {
  3. using namespace std::placeholders;
  4. this->timer_->cancel();
  5. if (!this->client_ptr_->wait_for_action_server()) {
  6. RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
  7. rclcpp::shutdown();
  8. }
  9. auto goal_msg = Fibonacci::Goal();
  10. goal_msg.order = 10;
  11. RCLCPP_INFO(this->get_logger(), "Sending goal");
  12. auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions();
  13. send_goal_options.goal_response_callback =
  14. std::bind(&FibonacciActionClient::goal_response_callback, this, _1);
  15. send_goal_options.feedback_callback =
  16. std::bind(&FibonacciActionClient::feedback_callback, this, _1, _2);
  17. send_goal_options.result_callback =
  18. std::bind(&FibonacciActionClient::result_callback, this, _1);
  19. this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
  20. }

这个函数的功能如下:

  1. 取消计时器(因此只调用一次)。

  2. 等待动作服务器启动。

  3. 实例化一个新的Fibonacci::Goal

  4. 设置响应、反馈和结果回调。

  5. 将目标发送到服务器。

当服务器接收并接受目标时,它将向客户机发送一个响应。该响应由goal_response_callback处理:

  1. void goal_response_callback(std::shared_future<GoalHandleFibonacci::SharedPtr> future)
  2. {
  3. auto goal_handle = future.get();
  4. if (!goal_handle) {
  5. RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
  6. } else {
  7. RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
  8. }
  9. }

假设目标被服务器接受,它将开始处理。任何给客户端的反馈都将被feedback_callback处理:

  1. void feedback_callback(
  2. GoalHandleFibonacci::SharedPtr,
  3. const std::shared_ptr<const Fibonacci::Feedback> feedback)
  4. {
  5. std::stringstream ss;
  6. ss << "Next number in sequence received: ";
  7. for (auto number : feedback->partial_sequence) {
  8. ss << number << " ";
  9. }
  10. RCLCPP_INFO(this->get_logger(), ss.str().c_str());
  11. }

当服务器完成处理后,它将向客户机返回一个结果。结果由result_callback处理:

  1. void result_callback(const GoalHandleFibonacci::WrappedResult & result)
  2. {
  3. switch (result.code) {
  4. case rclcpp_action::ResultCode::SUCCEEDED:
  5. break;
  6. case rclcpp_action::ResultCode::ABORTED:
  7. RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
  8. return;
  9. case rclcpp_action::ResultCode::CANCELED:
  10. RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
  11. return;
  12. default:
  13. RCLCPP_ERROR(this->get_logger(), "Unknown result code");
  14. return;
  15. }
  16. std::stringstream ss;
  17. ss << "Result received: ";
  18. for (auto number : result.result->sequence) {
  19. ss << number << " ";
  20. }
  21. RCLCPP_INFO(this->get_logger(), ss.str().c_str());
  22. rclcpp::shutdown();
  23. }

3.2编译动作客户端

打开action_tutorials_cpp/CMakeLists.txt,在find_package下添加:

  1. add_library(action_client SHARED
  2. src/fibonacci_action_client.cpp)
  3. target_include_directories(action_client PRIVATE
  4. $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  5. $<INSTALL_INTERFACE:include>)
  6. target_compile_definitions(action_client
  7. PRIVATE "ACTION_TUTORIALS_CPP_BUILDING_DLL")
  8. ament_target_dependencies(action_client
  9. "action_tutorials_interfaces"
  10. "rclcpp"
  11. "rclcpp_action"
  12. "rclcpp_components")
  13. rclcpp_components_register_node(action_client PLUGIN "action_tutorials_cpp::FibonacciActionClient" EXECUTABLE fibonacci_action_client)
  14. install(TARGETS
  15. action_client
  16. ARCHIVE DESTINATION lib
  17. LIBRARY DESTINATION lib
  18. RUNTIME DESTINATION bin)

编译:

  1. colcon build

3.3运行动作客户端

现在已经构建了动作客户端,可以运行它。首先,确保动作服务器在单独的终端中运行:

  1. ros2 run action_tutorials_cpp fibonacci_action_server

运行动作客户端:

  1. ros2 run action_tutorials_cpp fibonacci_action_client

现在可以看到被接受的目标日志消息、打印的反馈和最终的结果。

4.总结

在本文中,编写了一个C++动作服务器和客户端,并为它们配置目标、反馈和结果。

如果给您带来帮助,希望能给点个关注,以后还会陆续更新有关机器人的内容,点个关注不迷路~欢迎大家一起交流学习。

都看到这了,点个推荐再走吧~

未经允许,禁止转载。

ROS2学习之旅(21)——创建一个动作服务和客户节点(C++)的更多相关文章

  1. ROS2学习之旅(20)——创建一个动作消息

    本文用来自定义一个动作消息类型. 以下命令用来创建一个工作空间并建立一个功能包: mkdir -p action_ws/src cd action_ws/src ros2 pkg create act ...

  2. ROS2学习之旅(4)——理解ROS2 Graph中的节点

    ROS(2)图(ROS(2) graph)是一个同时处理数据的基于ROS2元素的网络,它包含了所有的可执行文件以及它们之间的连接.图中的基本元素包括:节点(nodes).话题(topics).服务(s ...

  3. ROS2学习之旅(15)——编写简单的服务和客户节点(C++)

    当节点使用服务进行通信时,发送数据请求的节点称为客户节点,响应请求的节点称为服务节点.请求和响应的结构由.srv文件决定. 本文的例子是一个简单的整数加法系统:一个节点请求两个整数的和,另一个节点响应 ...

  4. 使用PHP创建一个socket服务端

    与常规web开发不同,使用socket开发可以摆脱http的限制.可自定义协议,使用长连接.PHP代码常驻内存等.学习资料来源于workerman官方视频与文档. 通常创建一个socket服务包括这几 ...

  5. 为MongoDB创建一个Windows服务

    一:选型,根据机器的操作系统类型来选择合适的版本,使用下面的命令行查询机器的操作系统版本 wmic os get osarchitecture 二:下载并安装 附上下载链接 点击安装包,我这里是把文件 ...

  6. 【LINUX】——linux如何使用Python创建一个web服务

    问:linux如何使用Python创建一个web服务? 答:一句话,Python! 一句代码: /usr/local/bin/python -m SimpleHTTPServer 8686 > ...

  7. ng 通过factory方法来创建一个心跳服务

    <!DOCTYPE html> <html ng-app="myApp"> <head lang="en"> <met ...

  8. C# 创建一个WCF服务

    做代码统计,方便以后使用: app.config配置文件设置: <configuration> <system.serviceModel> <bindings> & ...

  9. ROS2学习之旅(13)——创建ROS2 功能包

    一个功能包可以被认为是ROS2代码的容器.如果希望能够管理代码或与他人共享代码,那么需要将其组织在一个包中.通过包,可以发布ROS2工作,并允许其他人轻松地构建和使用它. 在ROS2中,创建功能包使用 ...

随机推荐

  1. Go基础结构与类型01---常量变量表达式

    // 包名(main包下的main函数是程序的入口) package main // 导入sdk(software developing kit)中的fmt包 import "fmt&quo ...

  2. deeplearning搜索空间

    deeplearning搜索空间 搜索空间是神经网络搜索中的一个概念.搜索空间是一系列模型结构的汇集, SANAS主要是利用模拟退火的思想在搜索空间中搜索到一个比较小的模型结构或者一个精度比较高的模型 ...

  3. CUDA运行时 Runtime(一)

    CUDA运行时 Runtime(一)             一. 概述 运行时在cudart库中实现,该库通过静态方式链接到应用程序库cudart.lib和libcudart.a,或动态通过cuda ...

  4. 《python网络数据采集》笔记2

    1.网页表单与登陆窗口 Requests 库擅长处理那些复杂的 HTTP 请求.cookie.header(响应头和请求头)等内容. 1)表单提交 import requests #字段 params ...

  5. P2365 任务安排

    题目描述 n 个任务排成一个序列在一台机器上等待完成(顺序不得改变),这 n 个任务被分成若干批,每批包含相邻的若干任务. 从零时刻开始,这些任务被分批加工,第 i 个任务单独完成所需的时间为 ti​ ...

  6. 【NX二次开发】Block UI 指定位置

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  7. 【VBA】excel自动换名字打印

    源码: Sub m() For i = 1 To 100 ActiveSheet.PrintOut copies:=1 Cells(1, 1) = Sheets(2).Cells(i, 1) Next ...

  8. 【HTML】同页面锚点跳转

    跳转: <a href="#maodian001">去吧!</a> 锚点: <a id="maodian001"></ ...

  9. Python3中列表、字典、元组、集合的看法

    文首,我先强调一下我是一个弱鸡码农,这个随笔是在我学习完Python3中的元组.字典.列表,集合这四种常见数据的数据类型的一些感想,如果有什么不对的地方欢迎大家予以指正.谢谢大家啦 回归正题:这篇随笔 ...

  10. 无规矩不成方圆,聊一聊 Spring Boot 中 RESTful 接口设计规范

    在设计接口时,有很多因素要考虑,如接口的业务定位,接口的安全性,接口的可扩展性.接口的稳定性.接口的跨域性.接口的协议规则.接口的路径规则.接口单一原则.接口过滤和接口组合等诸多因素,本篇文章将简要分 ...