본문 바로가기
ROBOTICS/Turtlebot3 - Noetic

ROS Noetic : Server & Client

by 누워있는말티즈 2022. 8. 11.

앞서서 ROS service를 활용해보았다. 이는 서버-클라이언트 구조와 흡사함을 알 수 있다. 이번에는 실제로 서버-클라이언트의 구조를 만들어본다.

일단은 앞서 만들었던 closed_loop의 turtle_controller를 이용하며 화면의 좌측에 있으면 붉은 색, 우측에 있으면 녹색의 자취를 나타내는 형태를 만들 것이다.

이전 코드를 가져와서 bold 처리된 줄들을 추가해준다.

#!/usr/bin/env python3
import rospy
from turtlesim.msg import Pose # output of turtlesim
from geometry_msgs.msg import Twist # input for turtlesim

class TurtleControl:
    def __init__(self):
        rospy.init_node('turtle_controller')
        self.cmdmsg = Twist()
        self.pub = rospy.Publisher("/turtle1/cmd_vel", Twist, queue_size=10) 
        self.sub = rospy.Subscriber("/turtle1/pose", Pose, callback = self.pose_callback) 

        **# new function to call service /turtle1/set_pen
    def call_set_pen_service(r=0, g=0, b=0, width=4, off=0):
        try:
            # this is how we create service client : request
            set_pen = rospy.ServiceProxy("/turtle1/set_pen", SetPen)
            response = set_pen(r,g,b,width,off)
        # if service doesn't work we get exception
        except rospy.ServiceException as e:
            rospy.logwarn(e)**

        # we want to publish cmd_vel topic through this callback function
    def pose_callback(self,rcvmsg: Pose):
        if rcvmsg.x > 9.0 or rcvmsg.x < 2.0 or rcvmsg.y > 9.0 or rcvmsg.y < 2.0:
            self.cmdmsg.linear.x = 1.0
            self.cmdmsg.angular.z = 1.8
        else:
            self.cmdmsg.linear.x = 4.0
            self.cmdmsg.angular.z = 0.0

        self.pub.publish(self.cmdmsg)

if __name__=='__main__':
    rospy.loginfo("control node init")
        **# wait for service to be called
    rospy.wait_for_service("/turtle1/set_pen")**

    control_node = TurtleControl()
    rospy.spin()
  • 일단 service를 불러내기 위한 새로운 함수를 정의한다. parameter는 불러올 service의 parameter와 동일하게 맞춰주었다.

    try - except 구조로 rospy.ServiceProxy("service name", service type) 형태에 맞춘다.

    위 예시의 경우 rosservice로 확인하고 맞춰주었다.

    만약 service를 불러오지 못하면 exception을 토한다→except rospy.ServiceException as e

  • 다만! 이 줄은 pose callback처럼 자주 부를 필요가 없다.

      #pose callback 안에 있음
      if rcvmsg.x > 5.5:
              self.call_set_pen_service(255,0,0,4,0)
      else : 
              self.call_set_pen_service(0,255,0,4,0)

    따라서 이전의 x 좌표를 저장해주는 다른 변수를 만들어주고 현재와 비교해서 기준인 5.5를 지나갈 때만 색을 바꿔주는 모양으로 가본다.

      # __init__ 안에
      self.prev_x =0
    
      if rcvmsg.x > 5.5 and self.prev_x < 5.5:
              prev_x = rcvmsg.x
              self.call_set_pen_service(255,0,0,4,0)
      elif rcvmsg.x < 5.5 and self.prev_x > 5.5:
              prev_x = rcvmsg.x 
              self.call_set_pen_service(0,255,0,4,0)

    이러면 변화가 없을 때에는 불필요한 컴퓨팅을 하지 않아도 된다.

    전체 코드는 아래와 같다.

      #!/usr/bin/env python3
      import rospy
      from turtlesim.msg import Pose # output of turtlesim
      from geometry_msgs.msg import Twist # input for turtlesim
      from turtlesim.srv import SetPen
    
      class TurtleControl:
          def __init__(self):
              rospy.init_node('turtle_controller')
              self.prev_x =0
              self.cmdmsg = Twist()
              self.pub = rospy.Publisher("/turtle1/cmd_vel", Twist, queue_size=10) 
              self.sub = rospy.Subscriber("/turtle1/pose", Pose, callback = self.pose_callback) 
    
          # new function to call service /turtle1/set_pen
          def call_set_pen_service(self, r=0, g=0, b=0, width=4, off=0):
              try:
                  # this is how we create service client : request
                  set_pen = rospy.ServiceProxy("/turtle1/set_pen", SetPen)
                  response = set_pen(r,g,b,width,off)
              # if service doesn't work we get exception
              except rospy.ServiceException as e:
                  rospy.logwarn(e)
    
          # we want to publish cmd_vel topic through this callback function
          def pose_callback(self,rcvmsg: Pose):
              if rcvmsg.x > 9.0 or rcvmsg.x < 2.0 or rcvmsg.y > 9.0 or rcvmsg.y < 2.0:
                  self.cmdmsg.linear.x = 1.0
                  self.cmdmsg.angular.z = 1.8
              else:
                  self.cmdmsg.linear.x = 4.0
                  self.cmdmsg.angular.z = 0.0
    
              if rcvmsg.x > 5.5 and self.prev_x < 5.5:
                  self.prev_x = rcvmsg.x
                  rospy.loginfo("set color red")
                  self.call_set_pen_service(255,0,0,4,0)
              elif rcvmsg.x < 5.5 and self.prev_x > 5.5:
                  self.prev_x = rcvmsg.x 
                  rospy.loginfo("set color green")
                  self.call_set_pen_service(0,255,0,4,0)    
              self.pub.publish(self.cmdmsg)
    
      if __name__=='__main__':
          rospy.loginfo("control node init")
          # wait for service to be called
          rospy.wait_for_service("/turtle1/set_pen")
    
          control_node = TurtleControl()
          rospy.spin()

    위를 시행하면 다음과 같은 화면 결과를 볼 수 있다!!

반응형

댓글