요구사항
때때로 여러 개의 마스터가 필요하고 주제 콘텐츠를 교환해야 하는 경우가 있습니다. 이때 ros와 함께 제공되는 동일한 마스터를 설정하는 방법을 사용할 수 없습니다.
우리의 처리 방법은 서로 다른 마스터에서 실행되는 클라이언트와 서버를 구성하는 것입니다. 클라이언트는 master1 아래의 topic1을 구독한 다음 이를 tcp 프로토콜을 통해 master2 아래의 서버로 보냅니다(자체적으로 메시지 프로토콜 형식을 정의). . 메시지를 구문 분석한 후 master2 아래에 topic1을 게시하여 ros의 주제 프레임워크를 변경하지 않고도 master1에서 master2로 topic1 메시지를 전파할 수 있습니다.
아래에서 구현하는 것은 amcl_pose 주제를 변환하는 것입니다. 메시지 유형은 master1에서 master2로 전송되는 PoseWithCovarianceStamped이고 다른 주제 코드는
클라이언트 코드
#! /usr/bin/env python# -*- coding=utf-8 -*-import socketimport structimport rospyimport timefrom geometry_msgs.msg import PoseWithCovarianceStamped,PoseStamped#message proto# id | length | datadef send_msg(sock, msg ,id): # Prefix each message with a 4-byte id and length (network byte order) msg = struct.pack('>I',int(id)) + struct.pack('>I', len(msg)) + msg sock.sendall(msg)def odomCallback(msg): global odom_socket data = "" id = msg.header.seq print "send id: ",id x = msg.pose.pose.position.x y = msg.pose.pose.position.y #orientation orien_z = msg.pose.pose.orientation.z orien_w = msg.pose.pose.orientation.w data += str(x) + "," + str(y)+ "," + str(orien_z)+ "," + str(orien_w) send_msg(odom_socket,data,id) odom_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) odom_socket.connect(('127.0.0.1',8000)) rospy.init_node('server_node') rospy.Subscriber('/amcl_pose',PoseWithCovarianceStamped,odomCallback) rospy.spin()
서버 코드
#! /usr/bin/env python# -*- coding=utf-8 -*-import socketimport time,os,fcntlimport structimport rospyfrom geometry_msgs.msg import PoseWithCovarianceStamped,PoseStamped#message proto# id | length | datadef recv_msg(sock): try: # Read message length and unpack it into an integer raw_id = recvall(sock, 4) if not raw_id: return None id = struct.unpack('>I', raw_id)[0] print "receive id: ",id raw_msglen = recvall(sock, 4) if not raw_msglen: return None msglen = struct.unpack('>I', raw_msglen)[0] # Read the message data return recvall(sock, msglen) except Exception ,e: return Nonedef recvall(sock, n): # Helper function to recv n bytes or return None if EOF is hit data = '' while len(data) < n: packet = sock.recv(n - len(data)) if not packet: return None data += packet return data##把接受的数据重新打包成ros topic发出去def msg_construct(data): list = data.split(',') pose = PoseWithCovarianceStamped() pose.header.stamp = rospy.Time.now() pose.header.frame_id = "/map" pose.pose.pose.position.x = float(list[0]) pose.pose.pose.position.y = float(list[1]) pose.pose.pose.position.z = 0 pose.pose.pose.orientation.x = 0 pose.pose.pose.orientation.y = 0 pose.pose.pose.orientation.z = float(list[2]) pose.pose.pose.orientation.w = float(list[3]) pose.pose.covariance = [0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.06853891945200942] return pose#初始化socket,监听8000端口odom_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) odom_socket.bind(('',8000)) odom_socket.listen(10) (client,address) = odom_socket.accept() rospy.init_node("client_node") odom_pub = rospy.Publisher("/amcl_pose",PoseWithCovarianceStamped,queue_size=30) r = rospy.Rate(1000)#设置noblock,否则会阻塞在接听,下面while不会一直循环,只有在有数据才进行下一次循环fcntl.fcntl(client, fcntl.F_SETFL, os.O_NONBLOCK)while not rospy.is_shutdown(): data = recv_msg(client) if data: odom_pub.publish(msg_construct(data)) r.sleep()
결론
위 코드는 LAN에서 테스트되었으며 이미지 및 레이저 데이터를 전송할 때 데이터가 손실되지 않는지 확인할 수 있습니다.