最近刚开始接触学习ROS2,总是不是很理解rclpy.spin的内部实现逻辑。看了代码发现它是循环调用spin_once()。那么这个spin_once()又做了什么呢?
import rclpy
from rclpy.node import Node
import time
class HelloHZF(Node):
def __init__(self, name):
super().__init__(name)
print("Init Run!!!")
self.mytimer = self.create_timer(1, self.timercallback)
self.mytimer2 = self.create_timer(2, self.timercallback2)
print("Go On")
def timercallback(self):
self.get_logger().info("111111111111111111111111111")
def timercallback2(self):
self.get_logger().info("222222222222222222222222222")
def main(args=None):
rclpy.init(args=args)
node = HelloHZF("HaoMingZi_Node")
#rclpy.spin(node)
for i in range(0,10):
rclpy.spin_once(node)
node.destroy_node()
rclpy.shutdown()
在上述代码中,我在node的init做了两个timer,一个是间隔1s,一个是间隔2s。然后在main中调用时,让spin_once()执行10次。结果如下:
udeer@udeer-PC:~/dev_ws$ ros2 run aaaaa 111
Init Run!!!
Go On
[INFO] [1683687464.138775232] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687465.131338797] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687465.132454845] [HaoMingZi_Node]: 222222222222222222222222222
[INFO] [1683687466.131441968] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687467.131162605] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687467.132301120] [HaoMingZi_Node]: 222222222222222222222222222
[INFO] [1683687468.131334806] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687469.131437717] [HaoMingZi_Node]: 111111111111111111111111111
[INFO] [1683687469.132673857] [HaoMingZi_Node]: 222222222222222222222222222
[INFO] [1683687470.131421845] [HaoMingZi_Node]: 111111111111111111111111111
可见,其实spin就类似一个线程池,把node里面的callback都放入这个池子里。然后运行10次,刚好就是速度快的多、速度慢的少。即11111出两次、22222出一次。加起来一共出10次。
这是create_timer里的callback。subscription里的callback也是一样的作用么?我又做了如下实验。
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
# Create Listener Node
class Listener(Node):
def __init__(self, name):
super().__init__(name)
self.sub = self.create_subscription(String, "talk/hzftalk/mywords", self.listenCallback, 10)
#self.pub = self.create_publisher(String, "talk/hzftalk/mywords", 10)
#self.timer = self.create_timer(0.5, self.timer_callback)
def listenCallback(self, msg:String):
self.get_logger().info('I heard : %s' % msg.data)
def main(args=None):
rclpy.init(args=args)
node = Listener("ListenerName")
for i in range(10):
rclpy.spin_once(node)
node.destroy_node()
rclpy.shutdown()
然后启动listener 和 talker,发现其的确只运行了10遍callback,如下:
udeer@udeer-PC:~/dev_ws$ ros2 run aaaaa 333
[INFO] [1683688054.920636936] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688055.106918619] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688055.306843618] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688055.506869519] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688055.707022448] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688055.907058273] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688056.106918888] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688056.307077716] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688056.507085334] [ListenerName]: I heard : Hello Hzf
[INFO] [1683688056.708624266] [ListenerName]: I heard : Hello Hzf
因此,无论是timer里的callback、还是subscription里的callback,进入rclpy.spin()里的调度方式是一致的。并没有区别。