7.1.4-ROS-Kommunikationsmechanismus:

Tutorial zur Topic-Kommunikation

Einführung in die Topic-Kommunikation

In ROS ist die Topic-Kommunikation eine der grundlegenden Möglichkeiten für Knoten, Informationen auszutauschen. Dieses Tutorial führt Sie durch das Einrichten der grundlegenden Topic-Kommunikation mit C++ und Python. Wir implementieren ein einfaches Publisher-Subscriber-Modell, bei dem der Publisher Textnachrichten mit einer Frequenz von 10Hz sendet und der Subscriber diese Nachrichten empfängt und ausgibt.

J3010

1. Theoretisches Modell

Die Topic-Kommunikation umfasst drei Hauptkomponenten:

  • ROS Master: Verwaltet die Registrierung und Verbindung der Knoten.
  • Talker (Publisher): Sendet Nachrichten.
  • Listener (Subscriber): Empfängt Nachrichten.

Der ROS Master hilft beim Aufbau der Verbindungen zwischen Talkers und Listeners. Hier eine schrittweise Beschreibung des Kommunikationsablaufs:

  • Talker-Registrierung: Der Talker registriert sich beim ROS Master und gibt den Topic-Namen seiner Nachrichten an.
  • Listener-Registrierung: Der Listener registriert sich beim ROS Master und gibt das Topic an, das er abonnieren möchte.
  • Zuordnung: Der ROS Master ordnet Talker und Listener anhand des Topic-Namens zu und sendet die nötigen Verbindungsinformationen.
  • Verbindungsaufbau: Der Listener fordert eine Verbindung zum Talker an, der Talker bestätigt sie.
  • Nachrichtenaustausch: Sobald die Verbindung steht, beginnt der Talker damit, Nachrichten an den Listener zu senden.

Wichtige Punkte:

  • Der ROS Master wird nur für den Verbindungsaufbau benötigt.
  • Die Kommunikation läuft weiter, auch wenn der ROS Master nach Verbindungsaufbau heruntergefahren wird.
  • Es können mehrere Talker und Listener existieren und in beliebiger Reihenfolge gestartet werden.

2. Grundlegende Topic-Kommunikationsoperationen (C++)

Ziel: Erstellen eines Publisher-Knotens, der Textnachrichten mit 10Hz sendet, und eines Subscriber-Knotens, der die empfangenen Nachrichten ausgibt.

Schritte:

  1. Paket erstellen

    bash
    cd ~/seeed_ws/src/
    catkin_create_pkg listener_and_talker roscpp rospy std_msgs
    cd ~/seeed_ws/src/listener_and_talker/src
    touch listener.cpp talker.cpp
  2. Publisher-Implementierung:

    talker.cpp

    cpp
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    #include <sstream>
    
    int main(int argc, char *argv[]) {
        // Set locale for printing messages in the local language
        setlocale(LC_ALL, "");
        // Initialize the ROS node with a unique name
        ros::init(argc, argv, "talker");
        // Create a ROS node handle
        ros::NodeHandle nh;
        // Create a publisher object
        ros::Publisher pub = nh.advertise<std_msgs::String>("chatter", 10);
    
        std_msgs::String msg;
        std::string msg_front = "Hello Seeed";
        int count = 0;
        ros::Rate r(10); // 10Hz
    
        while (ros::ok()) {
            std::stringstream ss;
            ss << msg_front << count;
            msg.data = ss.str();
            pub.publish(msg);
            ROS_INFO("Sent message: %s", msg.data.c_str());
            r.sleep();
            count++;
        }
        return 0;
    }
  3. Subscriber-Implementierung:

    listener.cpp

    cpp
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    void doMsg(const std_msgs::String::ConstPtr& msg_p) {
        ROS_INFO("Heard: %s", msg_p->data.c_str());
    }
    
    int main(int argc, char *argv[]) {
        setlocale(LC_ALL, "");
        ros::init(argc, argv, "listener");
        ros::NodeHandle nh;
        ros::Subscriber sub = nh.subscribe<std_msgs::String>("chatter", 10, doMsg);
        ros::spin();
        return 0;
    }
  4. CMakeLists.txt-Konfiguration:

    Fügen Sie am Ende der CMakeLists.txt Ihres Pakets den folgenden Code hinzu:

    cmake
    add_executable(listener src/listener.cpp)
    add_executable(talker src/talker.cpp)
    
    target_link_libraries(listener ${catkin_LIBRARIES})
    target_link_libraries(talker ${catkin_LIBRARIES})

    J3010

  5. Code ausführen:

  • Öffnen Sie ein Terminal und starten Sie roscore:

    bash
    roscore
  • Öffnen Sie in einem neuen Terminal Ihren Workspace und führen Sie den Publisher-Knoten aus:

    bash
    rosrun listener_and_talker listener
  • In einem weiteren Terminal führen Sie den Subscriber-Knoten aus:

    bash
    rosrun listener_and_talker talker

    J3010

    J3010

Sie sollten Nachrichten sehen, die im Terminal veröffentlicht und empfangen werden.

3. Grundlegende Topic-Kommunikationsoperationen (Python)

Ziel: Erstellen eines Publisher-Knotens, der Textnachrichten mit 10Hz sendet, und eines Subscriber-Knotens, der die empfangenen Nachrichten ausgibt.

Schritte:

  1. Paket erstellen

    bash
    cd ~/seeed_ws/src/
    catkin_create_pkg listener_and_talker roscpp rospy std_msgs
    mkdir ~/seeed_ws/src/listener_and_talker/script
    cd ~/seeed_ws/src/listener_and_talker/script
    touch listener.py talker.py
  2. Publisher-Implementierung:

    talker.py

    python
    #!/usr/bin/env python
    import rospy
    from std_msgs.msg import String
    
    if __name__ == "__main__":
        rospy.init_node("talker_p")
        pub = rospy.Publisher("chatter", String, queue_size=10)
        msg = String()
        msg_front = "hello 你好"
        count = 0
        rate = rospy.Rate(10)  # 10Hz
    
        while not rospy.is_shutdown():
            msg.data = msg_front + str(count)
            pub.publish(msg)
            rospy.loginfo("Sent message: %s", msg.data)
            rate.sleep()
            count += 1
  3. Subscriber-Implementierung:

    listener.py

    python
    #!/usr/bin/env python
    import rospy
    from std_msgs.msg import String
    
    def doMsg(msg):
        rospy.loginfo("Heard: %s", msg.data)
    
    if __name__ == "__main__":
        rospy.init_node("listener_p")
        sub = rospy.Subscriber("chatter", String, doMsg, queue_size=10)
        rospy.spin()
  4. Ausführungsrechte vergeben:

    bash
     sudo chmod +x *.py
  5. CMakeLists.txt-Konfiguration:

    Fügen Sie am Ende der CMakeLists.txt Ihres Pakets den folgenden Code hinzu:

    cmake
    catkin_install_python(PROGRAMS
      scripts/talker.py
      scripts/listener.py
      DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
    )
  6. Code ausführen:

    • Öffnen Sie ein Terminal und starten Sie roscore:
      bash
      roscore
    • Öffnen Sie in einem neuen Terminal Ihren Workspace und führen Sie den Publisher-Knoten aus:
      bash
      rosrun listener_and_talker talker.py
    • In einem weiteren Terminal führen Sie den Subscriber-Knoten aus:
      bash
      rosrun listener_and_talker listener.py

Sie sollten Nachrichten sehen, die im Terminal veröffentlicht und empfangen werden.

Häufige ROS-Topic-Befehle

  • rostopic bw: Zeigt die Bandbreitennutzung eines Topics an
  • rostopic delay: Zeigt die Verzögerung eines Topics mit Header an
  • rostopic echo: Gibt Nachrichten auf dem Bildschirm aus
  • rostopic find: Sucht Topics nach Typ
  • rostopic hz: Zeigt die Veröffentlichungsfrequenz eines Topics an
  • rostopic info: Zeigt Informationen zu einem Topic an
  • rostopic list: Listet alle aktiven Topics auf
  • rostopic pub: Veröffentlicht Daten auf einem Topic
  • rostopic type: Gibt den Typ eines Topics aus

Einführung in die Service-Kommunikation

Die Service-Kommunikation in ROS unterscheidet sich von der Topic-Kommunikation darin, dass sie bidirektional ist. Sie erlaubt nicht nur das Senden von Nachrichten, sondern auch den Empfang von Antworten. Dieses Modell besteht aus zwei Hauptteilen:

  1. Client: Die Entität, die eine Anfrage sendet.
  2. Server: Die Entität, die die Anfrage verarbeitet und eine Antwort zurücksendet.

Wenn ein Client eine Anfrage an einen Server sendet, wartet er, bis der Server die Anfrage verarbeitet und eine Antwort zurückgibt. Dieses Vorgehen folgt einer „Anfrage-Antwort"-Struktur und schließt damit die Kommunikation ab.

Wie funktioniert es?

  • Knoten B (der Server) bietet eine Service-Schnittstelle, üblicherweise mit einem Namen wie /service_name.
  • Knoten A (der Client) sendet eine Anfrage an Knoten B.
  • Knoten B verarbeitet die Anfrage und sendet eine Antwort zurück.

Der Kommunikationsablauf lässt sich wie folgt darstellen:

  1. Talker-Knoten kündigt einen Service über den ROS Master an:

    • Der Talker-Knoten kündigt einen Service (z. B. advertiseService("bar", foo:1234)) über den ROS Master an und signalisiert damit seine Verfügbarkeit.
  2. Listener-Knoten sucht den Service über den ROS Master:

    • Der Listener-Knoten sendet eine Anfrage an den ROS Master, um den Service zu finden (z. B. lookupService("bar")).
  3. ROS Master gibt die Service-Adresse zurück:

    • Der ROS Master antwortet mit der Service-Adresse (z. B. foo:3456), damit sich der Listener-Knoten verbinden kann.
  4. Listener-Knoten fordert Daten vom Talker-Knoten an:

    • Der Listener-Knoten sendet eine Service-Anfrage an den Talker-Knoten, wobei XML/RPC für die Kommunikation verwendet wird.
  5. Talker-Knoten antwortet mit den angeforderten Daten:

    • Der Talker-Knoten verarbeitet die Anfrage und sendet die Antwortdaten über TCP zurück.

    J3010

Wichtige Punkte:

  • Der Client wird blockiert, bis er eine Antwort vom Server erhält.
  • Die Service-Kommunikation ist effizient, da sie nur bei Bedarf (d. h. wenn eine Anfrage gestellt wird) Ressourcen verbraucht.

Theoretisches Modell

Das Service-Kommunikationsmodell umfasst drei zentrale Komponenten:

  1. ROS Master: Verwaltet die Registrierung sowohl von Servern als auch von Clients und hilft, Verbindungen anhand übereinstimmender Service-Namen herzustellen.
  2. Server: Bietet den Service an.
  3. Client: Fordert den Service an.

Prozessübersicht:

  1. Server-Registrierung:

    • Der Server registriert sich beim ROS Master und gibt den Namen des bereitgestellten Service an.
  2. Client-Registrierung:

    • Der Client registriert sich beim ROS Master und gibt den Service an, den er nutzen möchte.
  3. Zuordnung und Verbindung:

    • Der ROS Master ordnet Client und Server anhand des Service-Namens zu und ermöglicht die Verbindung.
  4. Anfrage-Antwort-Zyklus:

    • Der Client sendet eine Anfrage an den Server, der diese verarbeitet und eine Antwort zurückgibt.

Topic- vs. Service-Kommunikation

Vergleichen wir diese beiden gängigsten ROS-Kommunikationsmethoden, um unser Verständnis zu vertiefen:

AspektTopic-KommunikationService-Kommunikation
KommunikationstypAsynchronSynchron
ProtokollTCP/IPTCP/IP
KommunikationsmodellPublish-SubscribeAnfrage-Antwort
BeziehungViele-zu-VieleEins-zu-Viele
EigenschaftenCallback-basiertRemote Procedure Call (RPC)
AnwendungsfälleKontinuierliche, hochfrequente DatenNiederfrequente, spezielle Aufgaben
BeispielVeröffentlichung von LiDAR-DatenAuslösen eines Sensors oder Aufnehmen eines Fotos

Hinweis: Remote Procedure Call (RPC) bedeutet, dass eine Funktion in einem anderen Prozess ausgeführt wird, als wäre sie lokal.

5. Erstellen eines benutzerdefinierten Service (srv) in ROS

Tauchen wir in ein praktisches Beispiel ein, in dem wir einen benutzerdefinierten Service erstellen, der zwei vom Client gesendete Ganzzahlen addiert. Der Server verarbeitet diese Anfrage und gibt die Summe an den Client zurück.

Schritte zur Implementierung:

  1. Ein neues Paket erstellen

    bash
    cd ~/seeed_ws/src
    catkin_create_pkg service_communication roscpp rospy std_msgs
    cd ~/seeed_ws
    catkin_make
  2. srv-Datei definieren: Die srv-Datei definiert die Struktur der Anfrage und der Antwort. In diesem Fall enthält die Anfrage zwei Ganzzahlen und die Antwort deren Summe. Erstellen Sie ein neues Verzeichnis namens srv in Ihrem Paket und fügen Sie eine Datei namens AddInts.srv hinzu:

    bash
     mkdir ~/seeed_ws/src/service_communication/srv
     cd ~/seeed_ws/src/service_communication/srv
     touch AddInts.srv

    Kopieren Sie Folgendes in AddInts.srv:

    srv
    int32 num1
    int32 num2
    ---
    int32 sum

    J3010

  3. package.xml aktualisieren: Fügen Sie die nötigen Abhängigkeiten zur Generierung von Nachrichtendateien in der package.xml des Pakets hinzu:

    xml
    <build_depend>message_generation</build_depend>
    <exec_depend>message_runtime</exec_depend>

    J3010

  4. CMakeLists.txt aktualisieren:

    • Fügen Sie die nötige Konfiguration zur Generierung der Service-Dateien in der CMakeLists.txt des Pakets hinzu:
      cmake
      find_package(catkin REQUIRED COMPONENTS
        roscpp
        rospy
        std_msgs
        message_generation
      )
      
      add_service_files(
        FILES
        AddInts.srv
      )
      
      generate_messages(
        DEPENDENCIES
        std_msgs
      )

      J3010

  5. Paket kompilieren:

    • Kompilieren Sie Ihr Paket, um die Service-Nachrichten-Header zu generieren:
      bash
      cd ~/seeed_ws
      catkin_make
      source devel/setup.bash

Service-Kommunikation implementieren (C++)

Dieses Beispiel zeigt, wie man Service-Kommunikation in ROS mit C++ implementiert. Wir erstellen einen einfachen Service, bei dem der Server zwei vom Client bereitgestellte Ganzzahlen addiert und die Summe zurückgibt.

1. Server-Implementierung:

add_two_ints_server.cpp

cpp
#include "ros/ros.h"
#include "service_communication/AddInts.h"

// Callback function to handle the client's request
bool add(service_communication::AddInts::Request &req,
         service_communication::AddInts::Response &res) {
    res.sum = req.num1 + req.num2;  // Compute the sum
    ROS_INFO("Request: a=%ld, b=%ld", (long int)req.num1, (long int)req.num2);
    ROS_INFO("Sending back response: [%ld]", (long int)res.sum);
    return true;
}

int main(int argc, char **argv) {
    ros::init(argc, argv, "add_two_ints_server");
    ros::NodeHandle nh;

    // Advertise the service to the ROS master
    ros::ServiceServer service = nh.advertiseService("add_two_ints", add);
    ROS_INFO("Ready to add two integers.");
    ros::spin();

    return 0;
}

2. Client-Implementierung:

add_two_ints_client.cpp

cpp
#include "ros/ros.h"
#include "service_communication/AddInts.h"
#include <cstdlib>

int main(int argc, char **argv) {
    ros::init(argc, argv, "add_two_ints_client");
    if (argc != 3) {
        ROS_INFO("Usage: add_two_ints_client X Y");
        return 1;
    }

    ros::NodeHandle nh;
    ros::ServiceClient client = nh.serviceClient<service_communication::AddInts>("add_two_ints");

    // Prepare the service request
    service_communication::AddInts srv;
    srv.request.num1 = atoll(argv[1]);
    srv.request.num2 = atoll(argv[2]);

    // Call the service and check if it was successful
    if (client.call(srv)) {
        ROS_INFO("Sum: %ld", (long int)srv.response.sum);
    } else {
        ROS_ERROR("Failed to call service add_two_ints");
        return 1;
    }

    return 0;
}

CMakeLists.txt-Konfiguration:

Fügen Sie unbedingt die folgenden Zeilen am Ende von CMakeLists.txt hinzu, um sowohl den Server als auch den Client zu kompilieren:

cmake
add_executable(add_two_ints_server src/add_two_ints_server.cpp)
add_executable(add_two_ints_client src/add_two_ints_client.cpp)

add_dependencies(add_two_ints_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(add_two_ints_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(add_two_ints_server ${catkin_LIBRARIES})
target_link_libraries(add_two_ints_client ${catkin_LIBRARIES})

Demo kompilieren und ausführen

Öffnen Sie ein Terminal:

bash
cd ~/seeed_ws
catkin_make
roscore

Öffnen Sie ein weiteres Terminal:

bash
cd ~/seeed_ws
source devel/setup.bash
 rosrun service_communication server

Öffnen Sie ein weiteres Terminal:

bash
cd ~/seeed_ws
source devel/setup.bash
rosrun service_communication client 1 5

J3010

Service-Kommunikation implementieren (Python)

Dieses Python-Beispiel erfüllt dieselbe Funktion wie das C++-Beispiel, in dem ein Service zum Addieren zweier Ganzzahlen verwendet wird.

Erstellen Sie unter dem Paket einen Ordner scripts und darin die Dateien add_two_ints_server.py und add_two_ints_client.py.

bash
cd ~/seeed/src/service_communication/
mkdir scripts
cd scripts
touch add_two_ints_server.py add_two_ints_client.py

1. Server-Implementierung:

add_two_ints_server.py

python
#!/usr/bin/env python
import rospy
from service_communication.srv import AddInts,AddIntsRequest, AddIntsResponse
def doReq(req):
    sum = req.num1 + req.num2
    rospy.loginfo("data:num1 = %d, num2 = %d, sum = %d",req.num1, req.num2, sum)
    resp = AddIntsResponse(sum)
    return resp
if __name__ == "__main__":
    rospy.init_node("addints_server_p")
    server = rospy.Service("AddInts",AddInts,doReq)
    rospy.spin()

2. Client-Implementierung:

add_two_ints_client.py

python
#!/usr/bin/env python

import sys
import rospy
from service_communication.srv import *

if __name__ == "__main__":
    if len(sys.argv) != 3:
        rospy.logerr("error")
        sys.exit(1)
    rospy.init_node("AddInts_Client_p")
    client = rospy.ServiceProxy("AddInts",AddInts)
    client.wait_for_service()
    req = AddIntsRequest()
    req.num1 = int(sys.argv[1])
    req.num2 = int(sys.argv[2]) 
    resp = client.call(req)
    rospy.loginfo("result:%d",resp.sum)

CMakeLists.txt-Konfiguration:

Fügen Sie für die Python-Skripte folgende Zeilen in Ihrer CMakeLists.txt hinzu:

cmake
catkin_install_python(PROGRAMS
  scripts/add_two_ints_server.py 
  scripts/add_two_ints_client.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

Demo kompilieren und ausführen

Öffnen Sie ein Terminal:

bash
cd ~/seeed_ws
catkin_make
roscore

Öffnen Sie ein weiteres Terminal:

bash
cd ~/seeed_ws
source devel/setup.bash
rosrun service_communication add_two_ints_server.py

Öffnen Sie ein weiteres Terminal:

bash
cd ~/seeed_ws
source devel/setup.bash
rosrun service_communication add_two_ints_client.py 1 5

Befehle der Service-Kommunikation

Um in ROS mit Services zu arbeiten, verwenden Sie den Befehl rosservice. Hier eine Liste gängiger rosservice-Befehle und ihrer Funktionen:

  • rosservice args: Gibt die für einen Service erforderlichen Argumente aus
  • rosservice call: Ruft einen Service mit den angegebenen Argumenten auf
  • rosservice find: Sucht Services nach Typ
  • rosservice info: Gibt Informationen zu einem Service aus
  • rosservice list: Listet alle aktiven Services auf
  • rosservice type: Gibt den Typ eines Service aus
  • rosservice uri: Gibt die ROSRPC-URI eines Service aus

Einführung in den ROS-Parameter-Server

Der ROS-Parameter-Server ist ein gemeinsam genutzter, multinutzerfähiger und über das Netzwerk zugänglicher Speicherbereich für Parameter. Er bietet eine Möglichkeit, Parameter zur Laufzeit zu speichern und abzurufen, die zur Konfiguration von Knoten oder zum Datenaustausch zwischen ihnen verwendet werden können. Parameter auf dem Server können verschiedener Datentypen sein, einschließlich Ganzzahlen, Booleans, Strings, Doubles, Listen und Dictionaries. Der Parameter-Server wird vom ROS Master verwaltet und Knoten interagieren mit ihm, indem sie Parameter setzen, abrufen oder löschen.

Theoretisches Modell des Parameter-Servers

Der Parameter-Server umfasst drei Hauptrollen:

  1. ROS Master: Verwaltet den Parameter-Server und fungiert als zentraler Speicher für Parameter.
  2. Talker: Ein Knoten, der Parameter auf dem Server setzt.
  3. Listener: Ein Knoten, der Parameter vom Server abruft.

Der Interaktionsprozess mit dem Parameter-Server umfasst typischerweise folgende Schritte:

  1. Parameter setzen (Talker):

    • Der Talker-Knoten sendet einen Parameter über RPC (Remote Procedure Call) an den Parameter-Server, einschließlich Name und Wert des Parameters. Der ROS Master speichert diesen Parameter in seiner Liste.
  2. Parameter abrufen (Listener):

    • Der Listener-Knoten fordert einen Parameter vom Parameter-Server an, indem er eine Anfrage mit dem Parameternamen sendet.
  3. Parameter zurückgeben (ROS Master):

    • Der ROS Master sucht den angeforderten Parameter in seinem Speicher und gibt den entsprechenden Wert an den Listener zurück.

    J3010

Unterstützte Datentypen:

  • 32-Bit-Ganzzahlen
  • Booleans
  • Strings
  • Doubles
  • ISO8601-Daten
  • Listen
  • Base64-codierte Binärdaten
  • Dictionaries

C++-Implementierung

Parameter setzen (C++):

Wir beginnen damit, mit zwei verschiedenen APIs verschiedene Arten von Parametern auf dem Parameter-Server zu setzen: ros::NodeHandle und ros::param.

set_parameters.cpp

cpp
#include "ros/ros.h"

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "set_parameters");

    std::vector<std::string> students = {"Alice", "Bob", "Charlie", "David"};
    std::map<std::string, std::string> friends = {{"John", "Doe"}, {"Jane", "Smith"}};

    // Using ros::NodeHandle to set parameters
    ros::NodeHandle nh;
    nh.setParam("int_param", 42);
    nh.setParam("double_param", 3.14159);
    nh.setParam("bool_param", true);
    nh.setParam("string_param", "Hello ROS");
    nh.setParam("vector_param", students);
    nh.setParam("map_param", friends);

    // Using ros::param to set parameters
    ros::param::set("int_param_param", 84);
    ros::param::set("double_param_param", 6.28318);
    ros::param::set("bool_param_param", false);
    ros::param::set("string_param_param", "Goodbye ROS");
    ros::param::set("vector_param_param", students);
    ros::param::set("map_param_param", friends);

    return 0;
}

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
add_executable(set_parameters src/set_parameters.cpp)
target_link_libraries(set_parameters ${catkin_LIBRARIES})

In diesem Beispiel:

  • Wir setzen verschiedene Arten von Parametern auf dem Parameter-Server, einschließlich Ganzzahlen, Doubles, Booleans, Strings, Vektoren und Maps.
  • Wir verwendeten sowohl die ros::NodeHandle- als auch die ros::param-API, um die Parameter zu setzen.

Parameter abrufen (C++):

Als Nächstes rufen wir die zuvor gesetzten Parameter ab.

get_parameters.cpp

cpp
#include "ros/ros.h"

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "get_parameters");

    // Using ros::NodeHandle to retrieve parameters
    ros::NodeHandle nh;
    int int_value;
    double double_value;
    bool bool_value;
    std::string string_value;
    std::vector<std::string> students;
    std::map<std::string, std::string> friends;

    nh.getParam("int_param", int_value);
    nh.getParam("double_param", double_value);
    nh.getParam("bool_param", bool_value);
    nh.getParam("string_param", string_value);
    nh.getParam("vector_param", students);
    nh.getParam("map_param", friends);

    ROS_INFO("Retrieved values:");
    ROS_INFO("int_param: %d", int_value);
    ROS_INFO("double_param: %.5f", double_value);
    ROS_INFO("bool_param: %d", bool_value);
    ROS_INFO("string_param: %s", string_value.c_str());

    for (const auto &student : students) {
        ROS_INFO("Student: %s", student.c_str());
    }

    for (const auto &friend_pair : friends) {
        ROS_INFO("Friend: %s = %s", friend_pair.first.c_str(), friend_pair.second.c_str());
    }

    return 0;
}

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
add_executable(get_parameters src/get_parameters.cpp)
target_link_libraries(get_parameters ${catkin_LIBRARIES})

In diesem Beispiel:

  • Wir rufen die auf dem Server gesetzten Parameter mithilfe der ros::NodeHandle-API ab.
  • Die abgerufenen Parameter werden zur Überprüfung im ROS-Log ausgegeben.

Parameter löschen (C++):

Schließlich sehen wir, wie man Parameter vom Parameter-Server löscht.

delete_parameters.cpp

cpp
#include "ros/ros.h"

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "delete_parameters");

    ros::NodeHandle nh;
    bool success;

    // Using ros::NodeHandle to delete parameters
    success = nh.deleteParam("int_param");
    ROS_INFO("Delete int_param: %s", success ? "Success" : "Failure");

    // Using ros::param to delete parameters
    success = ros::param::del("int_param_param");
    ROS_INFO("Delete int_param_param: %s", success ? "Success" : "Failure");

    return 0;
}

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
add_executable(delete_parameters src/delete_parameters.cpp)
target_link_libraries(delete_parameters ${catkin_LIBRARIES})

In diesem Beispiel:

  • Wir verwenden sowohl die ros::NodeHandle- als auch die ros::param-API, um Parameter vom Server zu löschen.
  • Der Erfolg der Löschung wird protokolliert.

2.2 Python-Implementierung

Parameter setzen (Python):

Setzen wir nun Parameter mit Python. Der Vorgang ist der C++-Version sehr ähnlich.

python
#!/usr/bin/env python

import rospy

if __name__ == "__main__":
    rospy.init_node("set_parameters_py")

    # Setting various types of parameters
    rospy.set_param("int_param", 42)
    rospy.set_param("double_param", 3.14159)
    rospy.set_param("bool_param", True)
    rospy.set_param("string_param", "Hello ROS")
    rospy.set_param("list_param", ["apple", "banana", "cherry"])
    rospy.set_param("dict_param", {"first_name": "John", "last_name": "Doe"})

    # Modifying a parameter
    rospy.set_param("int_param", 84)

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
catkin_install_python(PROGRAMS
  scripts/set_parameters_py.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

In diesem Beispiel:

  • Wir setzen verschiedene Arten von Parametern, einschließlich Ganzzahlen, Doubles, Booleans, Strings, Listen und Dictionaries.
  • Wir zeigen außerdem, wie man einen vorhandenen Parameter ändert.

Parameter abrufen (Python):

Als Nächstes rufen wir die gesetzten Parameter ab.

python
#!/usr/bin/env python

import rospy

if __name__ == "__main__":
    rospy.init_node("get_parameters_py")

    # Retrieving parameters
    int_value = rospy.get_param("int_param", 0)
    double_value = rospy.get_param("double_param", 0.0)
    bool_value = rospy.get_param("bool_param", False)
    string_value = rospy.get_param("string_param", "")
    list_value = rospy.get_param("list_param", [])
    dict_value = rospy.get_param("dict_param", {})

    rospy.loginfo("Retrieved values:")
    rospy.loginfo("int_param: %d", int_value)
    rospy.loginfo("double_param: %.5f", double_value)
    rospy.loginfo("bool_param: %s", bool_value)
    rospy.loginfo("string_param: %s", string_value)
    rospy.loginfo("list_param: %s", list_value)
    rospy.loginfo("dict_param: %s", dict_value)

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
catkin_install_python(PROGRAMS
  scripts/set_parameters_py.py
  scripts/get_parameters_py.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

In diesem Beispiel:

  • Wir verwenden rospy.get_param, um die auf dem Server gesetzten Parameter abzurufen.
  • Die abgerufenen Werte werden mit rospy.loginfo protokolliert.

Parameter löschen (Python):

Abschließend löschen wir Parameter mit Python vom Parameter-Server.

python
#!/usr/bin/env python

import rospy

if __name__ == "__main__":
    rospy.init_node("delete_parameters_py")

    try:
        rospy.delete_param("int_param")
        rospy.loginfo("int_param deleted successfully.")
    except KeyError:
        rospy.logwarn("int_param does not exist.")

    try:
        rospy.delete_param("non_existent_param")
        rospy.loginfo("non_existent_param deleted successfully.")
    except KeyError:
        rospy.logwarn("non_existent_param does not exist.")

Fügen Sie am Ende der CMakeLists.txt Ihres Pakets folgenden Code hinzu:

cmake
catkin_install_python(PROGRAMS
  scripts/set_parameters_py.py
  scripts/get_parameters_py.py
  scripts/delete_parameters_py.py
  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

In diesem Beispiel:

  • Wir versuchen, einen Parameter zu löschen, und behandeln den Fall, dass der Parameter nicht existiert, mittels Ausnahmebehandlung (KeyError).

Häufige Befehle des ROS-Parameter-Servers

rosparam enthält Kommandozeilenwerkzeuge zum Abrufen und Setzen von ROS-Parametern auf dem Parameter-Server unter Verwendung von YAML-codierten Dateien.

  • rosparam set: Einen Parameter setzen
  • rosparam get: Einen Parameter abrufen
  • rosparam load: Parameter aus einer externen Datei laden
  • rosparam dump: Parameter in eine externe Datei exportieren
  • rosparam delete: Einen Parameter löschen
  • rosparam list: Alle Parameter auflisten

Beispiele:

  • rosparam list: Alle Parameter auf dem Parameter-Server auflisten.
  • rosparam set <param_name> <value>: Einen Parameter mit einem bestimmten Wert setzen.
  • rosparam get <param_name>: Den Wert eines bestimmten Parameters abrufen.
  • rosparam delete <param_name>: Einen bestimmten Parameter löschen.
  • rosparam load <file_name.yaml>: Parameter aus einer YAML-Datei laden.
  • rosparam dump <file_name.yaml>: Die aktuellen Parameter in eine YAML-Datei exportieren.