ROS中的多线程

2023-05-16

ROS中的多线程

  • ROS多线程
    • 消息回调处理函数
    • 多线程
      • MultiThreadedSpinner
      • AsyncSpinner
    • callback传参
    • timer
    • timer加参数
  • C++中的多线程
  • Python中的多线程

ROS使用master管理节点,各节点之间可以使用同步异步多种通信方式,这种设计的思想本身其实鼓励把功能分别在多个节点实现,但是真实情况中处理复杂任务,多线程是必不可少的。

在ROS中可能使用到的线程可整体分为两种,ROS自旋处理线程,与语言库本身的线程,前者主要服务于callback数据的处理,后者处理同步或者异步的主动任务。

ros的C++接口:提供了丰富的接口。

ROS多线程

ROS提供的用于处理callback的线程机制。接口包括自旋,CallbackQueue队列处理,time callback等。

消息回调处理函数

ros::spin()和ros::spinOnce()。

两者区别在于,前者会循环,主程序运行到这里就不往下执行了,而后者只运行一次,在调用后还可以继续执行之后的程序。

如果程序含有相关的消息订阅函数,那么程序在执行过程中,除了主程序以外,ROS还会自动在后台按照规定的格式,接受订阅的消息,但是所接收到的消息并不是立刻就被处理,而是必须要等到消息回调处理函数执行的时候才被调用,这就是消息回到函数的原理。

ros::spinOnce()的用法相对来说很灵活,但往往需要考虑调用消息的时机,调用频率,以及消息池的大小,这些都要根据现实情况协调好,不然会造成数据丢包或者延迟的错误。

while(ros::ok()) {
	print();
	ros::spinOnce();
	loop_rate.slepp();
}

多线程

MultiThreadedSpinner

在构造过程中可以指定它所用线程数,但如果不指定线程数或者线程数设置为0,它将在每个cpu内核开辟一个线程。

#include "ros/ros.h"
#include "std_msgs/String.h"
 
#include <boost/thread.hpp>
 
/**
 * This tutorial demonstrates simple receipt of messages over the ROS system, using
 * a threaded Spinner object to receive callbacks in multiple threads at the same time.
 */
 
ros::Duration d(0.01);
 
class Listener
{
public:
  void chatter1(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter1: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
  void chatter2(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter2: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
  void chatter3(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter3: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
};
 
void chatter4(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO_STREAM("chatter4: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
  d.sleep();
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
 
  Listener l;
  ros::Subscriber sub1 = n.subscribe("chatter", 10, &Listener::chatter1, &l);
  ros::Subscriber sub2 = n.subscribe("chatter", 10, &Listener::chatter2, &l);
  ros::Subscriber sub3 = n.subscribe("chatter", 10, &Listener::chatter3, &l);
  ros::Subscriber sub4 = n.subscribe("chatter", 10, chatter4);
 
  /**
   * The MultiThreadedSpinner object allows you to specify a number of threads to use
   * to call callbacks.  If no explicit # is specified, it will use the # of hardware
   * threads available on your system.  Here we explicitly specify 4 threads.
   */
  ros::MultiThreadedSpinner s(4);
  ros::spin(s);
 
  return 0;
}

在这里插入图片描述

AsyncSpinner

异步线程处理,同时拥有start() 和stop() 函数,并且在销毁的时候会自动停止。

#include "ros/ros.h"
#include "std_msgs/String.h"
 
#include <boost/thread.hpp>
 
/**
 * This tutorial demonstrates simple receipt of messages over the ROS system, using
 * an asynchronous Spinner object to receive callbacks in multiple threads at the same time.
 */
 
ros::Duration d(0.01);
 
class Listener
{
public:
  void chatter1(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter1: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
  void chatter2(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter2: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
  void chatter3(const std_msgs::String::ConstPtr& msg)
  {
    ROS_INFO_STREAM("chatter3: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
    d.sleep();
  }
};
 
void chatter4(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO_STREAM("chatter4: [" << msg->data << "] [thread=" << boost::this_thread::get_id() << "]");
  d.sleep();
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
 
  Listener l;
  ros::Subscriber sub1 = n.subscribe("chatter", 10, &Listener::chatter1, &l);
  ros::Subscriber sub2 = n.subscribe("chatter", 10, &Listener::chatter2, &l);
  ros::Subscriber sub3 = n.subscribe("chatter", 10, &Listener::chatter3, &l);
  ros::Subscriber sub4 = n.subscribe("chatter", 10, chatter4);
 
  /**
   * The AsyncSpinner object allows you to specify a number of threads to use
   * to call callbacks.  If no explicit # is specified, it will use the # of hardware
   * threads available on your system.  Here we explicitly specify 4 threads.
   */
  ros::AsyncSpinner s(4);
  s.start();
 
  ros::Rate r(5);
  while (ros::ok())
  {
    ROS_INFO_STREAM("Main thread [" << boost::this_thread::get_id() << "].");
    r.sleep();
  }
 
  return 0;
}

在这里插入图片描述## 自定义队列处理线程

#include "ros/ros.h"
#include "ros/callback_queue.h"
#include "std_msgs/String.h"
 
#include <boost/thread.hpp>
 
/**
 * This tutorial demonstrates the use of custom separate callback queues that can be processed
 * independently, whether in different threads or just at different times.
 */
 
void chatterCallbackMainQueue(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO_STREAM("I heard: [ " << msg->data << "] in thread [" << boost::this_thread::get_id() << "] (Main thread)");
}
 
 
void chatterCallbackCustomQueue(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO_STREAM("I heard: [ " << msg->data << "] in thread [" << boost::this_thread::get_id() << "]");
}
 
/**
 * The custom queue used for one of the subscription callbacks
 */
ros::CallbackQueue g_queue;
void callbackThread()
{
  ROS_INFO_STREAM("Callback thread id=" << boost::this_thread::get_id());
 
  ros::NodeHandle n;
  while (n.ok())
  {
    g_queue.callAvailable(ros::WallDuration(0.01));
  }
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener_with_custom_callback_processing");
  ros::NodeHandle n;
 
  /**
   * The SubscribeOptions structure lets you specify a custom queue to use for a specific subscription.
   * You can also set a default queue on a NodeHandle using the NodeHandle::setCallbackQueue() function.
   *
   * AdvertiseOptions and AdvertiseServiceOptions offer similar functionality.
   */
  ros::SubscribeOptions ops = ros::SubscribeOptions::create<std_msgs::String>("chatter", 1000,
                                                                              chatterCallbackCustomQueue,
                                                                              ros::VoidPtr(), &g_queue);
  ros::Subscriber sub = n.subscribe(ops);
 
  ros::Subscriber sub2 = n.subscribe("chatter", 1000, chatterCallbackMainQueue);
 
  boost::thread chatter_thread(callbackThread);
 
  ROS_INFO_STREAM("Main thread id=" << boost::this_thread::get_id());
 
  ros::Rate r(1);
  while (n.ok())
  {
    ros::spinOnce();
    r.sleep();
  }
 
  chatter_thread.join();
 
  return 0;
}

在这里插入图片描述

callback传参

#include "ros/ros.h"
#include "std_msgs/String.h"
 
/**
 * This tutorial demonstrates a simple use of Boost.Bind to pass arbitrary data into a subscription
 * callback.  For more information on Boost.Bind see the documentation on the boost homepage,
 * http://www.boost.org/
 */
 
 
class Listener
{
public:
  ros::NodeHandle node_handle_;
  ros::V_Subscriber subs_;
 
  Listener(const ros::NodeHandle& node_handle): node_handle_(node_handle)
  {
  }
 
  void init()
  {
    subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 1")));
    subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 2")));
    subs_.push_back(node_handle_.subscribe<std_msgs::String>("chatter", 1000, boost::bind(&Listener::chatterCallback, this, _1, "User 3")));
  }
 
  void chatterCallback(const std_msgs::String::ConstPtr& msg, std::string user_string)
  {
    ROS_INFO("I heard: [%s] with user string [%s]", msg->data.c_str(), user_string.c_str());
  }
};
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener_with_userdata");
  ros::NodeHandle n;
 
  Listener l(n);
  l.init();
 
  ros::spin();
 
  return 0;
}

timer

#include "ros/ros.h"
 
/**
 * This tutorial demonstrates the use of timer callbacks.
 */
 
void callback1(const ros::TimerEvent&)
{
  ROS_INFO("Callback 1 triggered");
}
 
void callback2(const ros::TimerEvent&)
{
  ROS_INFO("Callback 2 triggered");
}
 
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
 
  ros::Timer timer1 = n.createTimer(ros::Duration(0.1), callback1);
  ros::Timer timer2 = n.createTimer(ros::Duration(1.0), callback2);
 
  ros::spin();
 
  return 0;
}

在这里插入图片描述

timer加参数

#include "ros/ros.h"
#include "cstring"
#include "iostream"
#include "han_agv/SocketClient.h"
 
#include "han_agv/VelEncoder.h"
 
using namespace std;
 
const float_t PI = 3.14159;
const int ENCODER_PER_LOOP = 900;
const float_t WHEEL_RADIUS = 0.075;
 
ClientSocket soc;
 
// ros_tutorials/turtlesim/tutorials/draw_square.cpp
void timerCallback(const ros::TimerEvent&, ros::Publisher vel_pub)
{
  ROS_INFO("Timer callback triggered");
  AGVDATA buffer;
  AGVSENSORS buffer_left_encoder_start;
  AGVSENSORS buffer_right_encoder_start;
 
//  if(soc.recvMsg(buffer) == 0)
//  {
//      cout << "Failed to receive message." << endl;
//      return;
//  }
 
  // Reverse the High and Low byte.
  double time_delay = 0.1;
  ros::Duration(time_delay).sleep ();
 
  buffer.SensorsData.WheelLeft_Encoder[0] = buffer.SensorsData.WheelLeft_Encoder[3];
  buffer.SensorsData.WheelLeft_Encoder[1] = buffer.SensorsData.WheelLeft_Encoder[2];
 
  buffer.SensorsData.WheelRight_Encoder[0] = buffer.SensorsData.WheelRight_Encoder[3];
  buffer.SensorsData.WheelRight_Encoder[1] = buffer.SensorsData.WheelRight_Encoder[2];
 
   han_agv::VelEncoder vel;
   vel.left_velocity = 1.0;
   vel.right_velocity = 2.0;
 
   vel_pub.publish(vel);
}
 
int main(int argc, char** argv)
{
        ros::init(argc, argv, "TCPDecode_node");
        ros::NodeHandle nh;
        ROS_INFO("create node successfully!");
 
        ros::Publisher vel_pub = nh.advertise<han_agv::VelEncoder>("HansAGV/encoder_vel", 1);
        ros::Timer decoder_timer = nh.createTimer(ros::Duration(0.1), boost::bind(timerCallback, _1, vel_pub));
        
        ros::spin();
}

C++中的多线程

简单使用

#include <thread>
#include <iostream>

void foo() {
    std::cout << "Hello C++11" << std::endl;
}

int main() {
    std::thread thread(foo);  // 启动线程foo
    thread.join();  // 等待线程执行完成
    
    return 0;
}

传入参数

#include <thread>
#include <iostream>

void hello(const char *name) {
    std::cout << "Hello " << name << std::endl;
}

int main() {
    std::thread thread(hello, "C++11");
    thread.join();

    return 0;
}

类成员函数作为线程入口

#include <thread>
#include <iostream>

class Greet
{
    const char *owner = "Greet";
public:
    void SayHello(const char *name) {
        std::cout << "Hello " << name << " from " << this->owner << std::endl;
    }
};
int main() {
    Greet greet;

    std::thread thread(&Greet::SayHello, &greet, "C++11");
    thread.join();

    return 0;
}
  • join:当前线程释放资源,优先执行join线程,等待join线程执行完毕,释放资源后前线程继续执行。
  • yield: 当前线程放弃执行,操作系统调度另一线程继续执行。
  • get_id: 获取线程 ID。
  • sleep_until: 线程休眠至某个指定的时刻(time point),该线程才被重新唤醒。
void sleep_until( const std::chrono::time_point<Clock,Duration>& sleep_time );
  • sleep_for: 线程休眠某个指定的时间片(time span),该线程才被重新唤醒,不过由于线程调度等原因,实际休眠时间可能比 sleep_duration 所表示的时间片更长。

Python中的多线程

python中的多线程是特殊的,经常提到伪线程的概念,主要因为没有真正提供并行处理,没有发挥出多核的运算优势。

为什么没有提供真正并行的线程运算?实则是为了解决资源抢占问题,为了解决问题,使用了GIL,GIL 的全名是 the Global Interpreter Lock (全局解释锁),是常规 python 解释器(当然,有些解释器没有)的核心部件。线程锁的概念应该都不陌生,GIL同样是用于保护 Python 内部对象的全局锁(在进程空间中唯一),保障了解释器的线程安全。
但很显然也带来了一个问题:每个时刻只有一条线程在执行,即使在多核架构中也是如此——毕竟,解释器只有一个。这就是伪线程的由来。

如何实现真正的并行,多进程,但是同时多进程又带来另一些问题:

  1. 进程之间不能共享内存,但线程之间共享内存非常容易。
  2. 操作系统在创建进程时,需要为该进程重新分配系统资源,相比创建线程的代价则小得多。

所以,还是老实先用多线程吧。

import threading
import time
from datetime import datetime

class MyThread(threading.Thread):
    def __init__(self, id):
        threading.Thread.__init__(self)
        self.id = id
    def run(self):
        time.sleep(5)
        print "子线程动作",threading.current_thread().name, datetime.now()
  
 if __name__ == "__main__":
    t1 = MyThread(999)
    t1.setDaemon(True)  # 添加守护线程!
    t1.start()
    t1.join()  # 添加join函数!
    for i in range(5):
        print "主线程动作",threading.current_thread().name, datetime.now()

部分转载出处:
原文链接:https://blog.csdn.net/yaked/article/details/50776224
菜鸟教程:https://www.runoob.com/w3cnote/cpp-std-thread.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS中的多线程 的相关文章

  • PX4 自定义bootloader生成

    本文主要是记录一下自己在这方面的学习 xff0c 方便以后回顾 xff0c 也希望对其他朋友有用 本着不重复造轮子的精神 xff0c 这里引文不在复制粘贴 xff0c 直接给出链接 生成bootloader的两种方式 以STM32H7作为主

随机推荐

  • PX4开发中遇到的一些问题和解决方法

    文章目录 前言正文1 仿真出现 FCU Preflight Fail Accel 0 uncalibrated等错误2 添加mavlink数据发送or提高数据发送频率3 PX4在不同硬件下的RC输入4 PX4 参数自定义5 电机输出顺序6
  • PX4自定义混控器

    文章目录 前言混控器简介混控器的启动自定义混控器参考 xff1a 前言 上一篇我对PX4的控制和输出的全流程都进行了较为详尽的分析 xff0c 本来想着之后的研究主要在四旋翼控制算法上 xff0c 不会定义啥新机型 xff0c 混控器的部分
  • 运行VINS,相机模型与参数的准备

    相机模型与参数 对于VINS来说 xff0c 相机的内参的准确是万分重要的 如果参数不对 xff0c 那么100 跑飞 xff0c 没商量 要想VINS可以很好的工作 xff0c 给出良好的相机内参是必须的 对于realsense系列的相机
  • MTF模块 PX4 光流模块详细配置

    对于研究无人机的新手 xff0c 直接飞手动模式 xff0c 可能过于困难 在室内测试时 xff0c 又没有GPS可用 为了安全和方便起见 xff0c 可以考虑选用光流模块 xff0c 降低入手难度 这里我们选择微空科技出品的MTF 01模
  • GNSS系列(3)------GNSS定位漂移讨论

    由于工作需要 xff0c 最近开启了GNSS系列文章的撰写工作 xff0c 发布于公司官网 xff0c 现将其同步至CSDN 原文链接 xff1a http onemo10086 com school article 196 小伙伴们 xf
  • ML302 OpenCPU系列(5)---Log工具的使用

    ML302 OpenCPU系列 xff08 5 xff09 Log工具的使用 一 使用串口助手抓取Log二 使用Coolwatcher抓取AP Log三 查看死机现场 工欲善其事 xff0c 必先利其器 Log是嵌入式开发中最重要的调试手段
  • 2017--就业分享之IT校招现状和面试经历

    在介绍自己整个春季和夏季实习求职经历之前 xff0c 先给大家公布一则新闻 2017届互联网校招薪酬报告 xff1a 先说下对 16 年 17 届校招的总体看法 xff1a 本该是个不大不小的年 xff0c 结果被华为一己之力搞成了个大年
  • Shell判断字符串是否相等,=两边需要有空格

    custom span class token operator 61 span span class token string 34 34 span span class token keyword if span span class
  • 学嵌入式系统设计的人应不应该看模拟电路基础

    我学嵌入式系统设计是首先从数字电路看起的 由于数字电路这门课程在大一的时候就学过 xff0c 所以觉得略看就能看懂 xff0c 也算是把这门课复习了一遍 但是当我看到存储器和可编程控件这一章时 xff0c 里面讲到存储单元主要是由半导体组成
  • 使用Python爬取淘宝两千款套套

    各位同学们 xff0c 好久没写原创技术文章了 xff0c 最近有些忙 xff0c 所以进度很慢 xff0c 给大家道个歉 gt 警告 xff1a 本教程仅用作学习交流 xff0c 请勿用作商业盈利 xff0c 违者后果自负 xff01 如
  • ​揭秘国内首个进入Apache的高校顶级项目——Apache IoTDB

    本文约4200字 xff0c 建议阅读10 43 分钟 本文与你分享有关开源数据库项目成长 开源社区治理 加速赋能企业等方面的观点与见解 近年来 xff0c 随着人工智能 物联网的兴起 xff0c 大数据成为重要的生产资料 xff0c 而时
  • 收藏 | 一张地图带你玩转机器学习(附资源)

    本文来自AI学习与实践平台SigAI 本文共16965字 xff0c 建议阅读20 43 分钟 本文对常用的机器学习和深度学习算法进行了总结 xff0c 整理出它们之间的关系 xff0c 以及每种算法的核心点 xff0c 各种算法之间的比较
  • python代码获取远程电脑IP

    实时的使用邮箱发送IP地址到指定邮箱 使用python代码封装好的软件 xff1a 链接 xff1a https pan baidu com s 1Flz7HHtZM0w3HGDeF 4BhQ pwd 61 yxy2 提取码 xff1a y
  • win11旗舰版安装WSL子系统和环境-3Ubuntu换源

    Wsl2开启 Ubuntu换源 https blog csdn net WPwalter article details 101508601 这个blog是进行系统安装WSL2 的 Linux 第一步 xff1a 启用虚拟机平台和 Linu
  • win11旗舰版安装WSL子系统和环境-12配置SSH(Win远程连接)

    配置SSH Win远程连接 https blog csdn net weixin 43897590 article details 109446339 utm medium 61 distribute pc relevant downloa
  • win11旗舰版安装WSL子系统和环境-17Xshell连接wsl子系统的ssh

    https blog csdn net w4187402 article details 85992013 那么问题找到了 出现这样的问题只能是ip冲突 xff0c 其他同事的服务器占用了我当前服务器的ip地址 xff0c 我现在连接的服务
  • 超好用的word插件-工作和科研

    Word精灵7 0版 可以很好地处理图片 xff0c 转换 xff0c 以及各种批量处理操作 GrammarlyAddInSetup 可以很好地校对英文错误 xff0c 单词以及语法错误 xff0c 但被动语态不太行 链接 xff1a ht
  • Adobe Premiere Pro 2023 SP(未完成)

    需要添加
  • 一个程序员所应该具备的精神

    所谓障碍都是主观上的 如果你想研发什么新的技术 xff0c 只需要在冰箱里放满食物和饮料 xff0c 再有一台便宜的计算机 xff0c 和以之献身的决心 xff0c 你即可拥有任何你想拥有的编程深度 xff01 John Carmack
  • ROS中的多线程

    ROS中的多线程 ROS多线程消息回调处理函数多线程MultiThreadedSpinnerAsyncSpinner callback传参timertimer加参数 C 43 43 中的多线程Python中的多线程 ROS使用master管