ROS2-kerncommunicatie

06 Knooppunt

06 Knooppunten (Nodes)

6.1 Samenvatting van knooppunten

6.1.1 Wat is een knooppunt

Een knooppunt is de meest basale rekeneenheid in ROS 2. Een knooppunt is een proces dat de ROS 2 API gebruikt om met andere knooppunten te communiceren. Elk knooppunt is normaal gesproken verantwoordelijk voor specifieke functies, zoals het lezen van sensorgegevens, het verwerken van gegevens, het besturen van implementeerders, enz.

6.1.2 Kenmerken van knooppunten

KenmerkenAnnotaties
LichtgewichtEen uitvoerbaar bestand kan meerdere knooppunten bevatten
DistributieKnooppunt kan op verschillende machines draaien.
OntkoppeldCommunicatie tussen knooppunten via interface, niet rechtstreeks afhankelijk
GroepeerbaarMeerdere knooppunten om complexe functies uit te voeren
Onafhankelijke levenscyclusElk knooppunt onafhankelijk starten en sluiten

6.1.3 Knooppuntnaamgevingsregels

Knooppuntnaam moet uniek zijn (in dezelfde naamruimte)

Alleen letters, cijfers en onderstrepingstekens kunnen worden opgenomen

Hoofdlettergevoelig

Aanbevolen gebruik van beschrijvende naam

Voorbeeld van naam:

KnooppuntnaamEvaluatie
Camera_driverUitstekend.
path_plannerUitstekend.
Node1Niet aanbevolen (geen beschrijving)
Oh, my-node.Ongeldig (met afbreekstreepje)

6.2 Hello World Node-case

6.2.1 Python-kit maken

workspace vervangt het werkelijke werkruimtepad

bash
cd workspace/src
ros2 pkg create pkg_helloworld_py --build-type ament_python --dependencies rclpy --node-name helloworld

6.2.2 Voorbereiding van codes

bash
import rclpy
from rclpy.node import Node
import time

class HelloWorldNode(Node):
  def __init__(self, name):
  super().__init__(name)
  while rclpy.ok():
  self.get_logger().info("Hello World")
  time.sleep(0.5)

def main(args=None):
  rclpy.init(args=args)
  node = HelloWorldNode("helloworld")
  rclpy.spin(node)
  node.destroy_node()
  rclpy.shutdown()
bash
colcon build --packages-select pkg_helloworld_py
source install/setup.bash
ros2 run pkg_helloworld_py helloworld

6.3 Volgende stappen

1.07 Topic-communicatie

2.08 Service-communicatie

07 Topic-communicatie

07 Topic-nieuwsbrief (Topics)

7.1 Samenvatting van topic-communicatie

7.1.1 Wat is topic-communicatie?

Topic is het mechanisme voor asynchrone communicatie tussen ROS 2-knooppunten, met behulp van de publicatie-/abonnementsmodus (Pub/Sub). Het uitgeversknooppunt geeft nieuws uit aan het topic, en het abonneeknooppunt ontvangt informatie van het topic, en geen van beide hoeft de ander te kennen.

7.1.2 Kenmerken van topic-communicatie

KenmerkenBeschrijvingToepassingsscène
Asynchrone communicatieVerzender wacht niet op de reactie van de abonneeSensorgegevensstroom
Veel-op-veelMeerdere uitgevers en abonneesDatatransmissie
Zwak gekoppeldOntkoppelingModulair ontwerp
StreamoverdrachtLopende datastromenContinue monitoring

7.1.3 Topic-naamgevingsregels

RegelAnnotaties
Moet beginnen (globale naamruimte) of relatieve naam
Gebruik kleine letters, cijfers en onderstrepingstekens
Gebruik / om naamruimteniveaus te scheiden
Vermijd het behouden van namen

Voorbeeld van naam:

TopicnaamEvaluatie
/cmd_velStandaarden, aanbevolen
/camera/image_rawNiveau duidelijk. Aanbevolen.
/sensor/front_camera/imageNaamruimte, aanbevolen.
/MyTopicNiet aanbevolen (in hoofdletters)
add_velRelatieve naam (knooppuntnaamruimte toegevoegd)

7.2 Communicatiecases

7.2.1 Nieuw functioneel pakket

bash
cd ~/workspaces/src
ros2 pkg create pkg_topic --build-type ament_python --dependencies rclpy --node-name publisher_demo

7.2.2 De auteur bereikt

bash
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class Topic_Pub(Node):
  def __init__(self,name):
  super().__init__(name)
  self.pub = self.create_publisher(String,"/topic_demo",1)
  self.timer = self.create_timer(1,self.pub_msg)
  def pub_msg(self):
  msg = String()
  msg.data = "Hi,I send a message."
  self.pub.publish(msg)

def main():
  rclpy.init()
  pub_demo = Topic_Pub("publisher_node")
  rclpy.spin(pub_demo)
  pub_demo.destroy_node()
  rclpy.shutdown()

7.2.3 Configuratiebestanden bewerken

7.2.4 Functioneel pakket compileren

bash
cd ~/workspace
colcon build --packages-select pkg_topic
source install/setup.bash

7.2.5 Vrijgaveknooppunten uitvoeren

bash
ros2 run pkg_topic publisher_demo
ros2 topic list
ros2 topic echo /topic_demo

7.2.6 Een abonnee aanmaken

bash
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Topic_Sub(Node):
  def __init__(self,name):
  super().__init__(name)
  self.sub = self.create_subscription(String,"/topic_demo",self.sub_callback,1)
  def sub_callback(self,msg):
  self.get_logger().info(msg.data)

def main():
  rclpy.init()
  sub_demo = Topic_Sub("subscriber_node")
  rclpy.spin(sub_demo)
  sub_demo.destroy_node()
  rclpy.shutdown()

7.2.7 Configuratiebestanden bewerken

7.2.8 Functioneel pakket compileren

bash
cd ~/workspace
colcon build --packages-select pkg_topic
source install/setup.bash

7.2.9 Operationele knooppunten

bash
ros2 run pkg_topic publisher_demo
ros2 run pkg_topic subscriber_demo

7.3 Volgende stappen

1.08 Service-communicatie

2.09 Action-communicatie

08 Service-communicatie

08 Service-communicatie (Services)

8.1 Overzicht van service-communicatie

8.1.1 Wat is service-communicatie

Service is het mechanisme voor gesynchroniseerde communicatie tussen knooppunten in ROS 2, met behulp van het client/server-model. De client verzendt het verzoek, de service verwerkt het en stuurt de respons terug.

8.1.2 Services vs topics

KenmerkServicesTopics
CommunicatiemodusSync (verzoek-respons)Async (publicatie-abonnement)
VerbindingEén op één.Veel-op-veel.
ToepassingsscèneKorte operatiequeryLopende datastromen
BlokClient blokkeert tijdens wachten.Geen blokkering.
RetourwaardeWe moeten de respons retourneren.Geen respons

8.1.3 Definitie van servicetype

bash
# File: example interfaces/srv/AddTwoInts.srv
int64 a
int64 b
---
int64 sum

8.2 Voorbeelden van service-communicatie

8.2.1 Nieuw functioneel pakket

bash
ros2 pkg create pkg_service --build-type ament_python --dependencies rclpy --node-name server_demo

8.2.2 Een service-eindpunt aanmaken

bash
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Service_Server(Node):
  def __init__(self,name):
  super().__init__(name)
  self.srv = self.create_service(AddTwoInts, '/add_two_ints', self.Add2Ints_callback)
  def Add2Ints_callback(self,request,response):
  response.sum = request.a + request.b
  print("response.sum = ",response.sum)
  return response
def main():
  rclpy.init()
  server_demo = Service_Server("publisher_node")
  rclpy.spin(server_demo)
  server_demo.destroy_node()
  rclpy.shutdown()
bash
ros2 interface show example_interfaces/srv/AddTwoInts

8.2.3 Configuratiebestanden bewerken

bash
'server_demo = pkg_service.server_demo:main',

8.2.4 Functioneel pakket compileren

bash
colcon build --packages-select pkg_service
source install/setup.bash
ros2 run pkg_service server_demo
bash
ros2 service list
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1,b: 4}"

8.2.5 Client maken

bash
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Service_Client(Node):
  def __init__(self,name):
  super().__init__(name)
  self.client = self.create_client(AddTwoInts,'/add_two_ints')
  while not self.client.wait_for_service(timeout_sec=1.0):
  print("service not available, waiting again...")
  self.request = AddTwoInts.Request()

  def send_request(self):
  self.request.a = 10
  self.request.b = 90
  self.future = self.client.call_async(self.request)

def main():
  rclpy.init()
  service_client = Service_Client("client_node")
  service_client.send_request()
  while rclpy.ok():
  rclpy.spin_once(service_client)
  if service_client.future.done():
  try:
  response = service_client.future.result()
  print("Result = ",response.sum)
  except Exception as e:
  service_client.get_logger().info('Service call failed %r' % (e,))
  break
  service_client.destroy_node()
  rclpy.shutdown()

8.2.6 Configuratiebestanden bewerken

bash
'client_demo = pkg_service.client_demo:main'

8.2.7 Functioneel pakket compileren

bash
cd ~/workspace
colcon build --packages-select pkg_service
source install/setup.bash
ros2 run pkg_service server_demo
bash
source install/setup.bash
ros2 run pkg_service client_demo

8.3 Volgende stappen

1.09 Action-communicatie - Action-communicatie leren (lange missie)

  1. 10 TF2 coördinatentransformatie - aangepast servicetype maken

09 Action-communicatie

09 Action-communicatie (Actions)

9.1 Samenvatting van action-communicatie

9.1.1 Wat is bewegingscommunicatie?

Action is het communicatiemechanisme dat in ROS 2 wordt gebruikt om lange opdrachten te verwerken. Vergelijkbaar met services zijn acties een client-server-modus, maar ondersteunen:

  • Realtime feedback tijdens de uitvoering van het mandaat

  • Client kan een actieve opdracht annuleren.

  • Geschikt voor het afhandelen van bewerkingen die seconden tot minuten kunnen duren.

9.1.2 Action vs services

KenmerkServiceAction
Lengte van de toepassingKorte bewerking (ms-s)Lange missies (seconden-minuten)
FeedbackGeen realtime feedbackVerzend continu feedback
AnnulerenNiet ondersteundMaar annuleren.
BlokClientblokUitschakelen
ToepassingsscèneQuery, eenvoudige bewerkingenNavigatie, vastleggen

9.2 Action-communicatiecases

9.2.1 Nieuw functionele kit

bash
ros2 pkg create --build-type ament_cmake pkg_interfaces
bash
int64 num
---
int64 sum
---
float64 progress
bash
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<depend>action_msgs</depend>
<member_of_group>rosidl_interface_packages</member_of_group>
bash
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "action/Progress.action")
bash
cd ~/workspace
colcon build --packages-select pkg_interfaces
bash
ros2 interface show pkg_interfaces/action/Progress
bash
ros2 pkg create pkg_action --build-type ament_python --dependencies rclpy pkg_interfaces --node-name action_server_demo

4. Service-eind-realisatie

4.1 Een serviceprovider maken

bash
import time
import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node

from pkg_interfaces.action import Progress

class Action_Server(Node):
  def __init__(self):
  super().__init__('progress_action_server')
  self._action_server = ActionServer(
  self,
  Progress,
  'get_sum',
  self.execute_callback)
  self.get_logger().info('The action server has started!')

  def execute_callback(self, goal_handle):
  self.get_logger().info('Starting task execution...')
  feedback_msg = Progress.Feedback()
  total = 0
  for i in range(1, goal_handle.request.num + 1):
  total += i
  feedback_msg.progress = i / goal_handle.request.num
  self.get_logger().info('Continuous feedback: %.2f' % feedback_msg.progress)
  goal_handle.publish_feedback(feedback_msg)
  time.sleep(1)

  goal_handle.succeed()
  result = Progress.Result()
  result.sum = total
  self.get_logger().info('Task completed!')
  return result

def main(args=None):
  rclpy.init(args=args)
  Progress_action_server = Action_Server()
  rclpy.spin(Progress_action_server)
  Progress_action_server.destroy_node()
  rclpy.shutdown()

4.2 Configuratiebestanden bewerken

bash
'action_server_demo = pkg_action.action_server_demo:main',

4.3 Functioneel pakket compileren

bash
cd ~/workspace
colcon build --packages-select pkg_action
source install/setup.bash
ros2 run pkg_action action_server_demo
bash
ros2 action list
ros2 action send_goal /get_sum pkg_interfaces/action/Progress "{num: 10}"

5. Client bereikt

5.1 Client maken