Ros
27 May 2023

ROS Server

ROS Learning Notes

ROS Learning Notes 06

image

Keypoints

  • ROS Server

image

image

ROS Server

  • A server is a node that provides a service. To publish a service, a node must advertise it.
  • Example: to publish a command
    • cpp:
      • cpp file:
          // to excute turtle_command service, service data type is std_srvs::Trigger
        
          #include <ros/ros.h>
          #include <std_srvs/Trigger.h>
          #include <geometry_msgs/Twist.h>
        
          ros::Publisher turtle_vel_pub;
          bool pubCommand = false;
        
          // arg: req, res. req here is empty, res contains two variables: bool success and string message.
          bool commandCallback(std_srvs::Trigger::Request &req, std_srvs::Trigger::Response &res)
          {
              pubCommand = !pubCommand;   // initial pubCommand is false, when receive the service request, change pubCommand state. 
              res.success = true;
              res.message = "change turtle command state!";
              ROS_INFO("send turtle velocity command[%s]", pubCommand == true ? "true" : "false");
              return true;
          }
        
          int main(int argc, char **argv)
          {   
              //  init node
              ros::init(argc, argv, "turtle_command_server");
              ros::NodeHandle n;
        
              // create service server: command_service, register callback function: commandCallback. Define the service name: /turtle_command.
              //  When receive the service "/turtle_command" request, call the callback function.
              ros::ServiceServer command_service = n.advertiseService("/turtle_command", commandCallback);    //.advertiseService() is a function of NodeHandle class, is to create a service server.
        
              // create publisher: turtle_vel_pub, define the topic name: /turtle1/cmd_vel, define the message type: geometry_msgs::Twist, queue size: 10
              turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel", 10);
        
              ROS_INFO("ready to receive turtle command");
        
              ros::Rate loop_rate(10);    // set the loop rate: 10Hz
              while (ros::ok())
              {
                  ros::spinOnce();    // to check the callback function queue. If there is a callback function, call it. If not, continue the while loop.
                  if (pubCommand)     // if pubCommand is true, publish the velocity command
                  {
                      geometry_msgs::Twist vel_msg;
                      vel_msg.linear.x = 0.5;
                      vel_msg.angular.z = 0.2;
                      turtle_vel_pub.publish(vel_msg);
                  }
                  loop_rate.sleep();  // sleep to keep the loop rate: 10Hz
              }
        
              return 0;
          }
        
      • CMakeLists.txt:
          add_executable(turtle_command_server src/turtle_command_server.cpp) ## to compile the cpp file into executable file: turtle_command_server. src is the folder name, turtle_command_server.cpp is the cpp file name.
          target_link_libraries(turtle_command_server ${catkin_LIBRARIES})    ## to link the executable file with catkin_LIBRARIES
        

        also, uncomment the following line in CMakeLists.txt:

          catkin_package(
          #  INCLUDE_DIRS include
          #  LIBRARIES learning_service
          CATKIN_DEPENDS geometry_msgs roscpp rospy turtlesim ## here is to add CATKIN_DEPENDS geometry_msgs roscpp rospy turtlesim
          #  DEPENDS system_lib
          )
        
      • source devel/setup.bash
      • roscore
      • rosrun turtlesim turtlesim_node
      • rosrun learning_service turtle_command_server
      • rosservice call /turtle_command "{}" // to call the service, here is to call the service “/turtle_command”, “{}” is the request data, here is empty.
    • Python:
          #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      
      import rospy
      from geometry_msgs.msg import Twist
      import thread, time
      from std_srvs.srv import Trigger, TriggerResponse
      
      # global variable
      pubCommand = False
      turtle_vel_pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
      
      def command_thread():
          while True:
              if pubCommand:
                  twist = Twist()
                  twist.linear.x = 0.5
                  twist.angular.z = 0.2
                  turtle_vel_pub.publish(twist)
              time.sleep(0.1)
                  
      def commandCallback(req):
          global pubCommand   # to get the global variable
          pubCommand = not pubCommand
          rospy.loginfo("Change turtle command state to " + str(pubCommand))
          # return TriggerResponse(success, message). TriggerResponse is a class, success and message are the parameters of the class
          return TriggerResponse(True, "Change turtle command state to " + str(pubCommand))
      
      def turtle_command_server():
          # init a node
          rospy.init_node('turtle_command_server')
              
          # rospy.Service is a class, turtle_command is the name of the service, Trigger is the type of the service, commandCallback is the callback function
          s = rospy.Service('turtle_command', Trigger, commandCallback)
          print("Waiting for command")
              
          # thread is a module, start_new_thread is a function to start multi thread (Python is usually one thread), command_thread is the thread function
          # There is no ros::spinOnce() in python, so we need to use thread to publish the command
          thread.start_new_thread(command_thread, ())
              
          # spin() simply keeps python from exiting until this node is stopped
          rospy.spin()
              
      if __name__ == "__main__":
          turtle_command_server()
      

      Then run the following commands:

      chmod 777 scripts/turtle_command_server.py
      python scripts/turtle_command_server.py or rosrun learning_service turtle_command_server.py
      

Tags:
0 comments