Je viens de commencer à apprendre ROS2 récemment et je ne comprends toujours pas très bien la logique de mise en œuvre interne de rclpy.spin. Après avoir regardé le code, j'ai découvert qu'il appelait spin_once() en boucle. Alors, que fait ce 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()
Dans le code ci-dessus, j'ai créé deux timers dans l'initialisation du nœud, l'un avec un intervalle de 1 s et l'autre avec un intervalle de 2 s. Ensuite, lorsqu'il est appelé dans main, laissez spin_once() s'exécuter 10 fois. Le résultat est le suivant :
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
On peut voir que le spin est en fait similaire à un pool de threads, et tous les rappels du nœud sont placés dans ce pool. Ensuite, exécutez-le 10 fois, ce qui s'avère être beaucoup plus rapide et moins lent. Autrement dit, 11111 sort deux fois et 22222 sort une fois. Un total de 10 fois au total.
Il s'agit du rappel dans create_timer. Le rappel en abonnement a-t-il la même fonction ? J'ai refait l'expérience suivante.
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()
Ensuite, démarrez l'auditeur et le locuteur et constatez qu'ils n'exécutent le rappel que 10 fois, comme suit :
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
Ainsi, qu'il s'agisse d'un rappel en timer ou d'un rappel en abonnement, la méthode de planification saisie dans rclpy.spin() est la même. Il n'y a pas de différence.