【问题标题】:ROS subscriber to socket in pythonROS订阅者到python中的套接字
【发布时间】:2020-06-01 09:42:18
【问题描述】:

大家好,我想实现一个 python ros 节点,它订阅一个主题(在我的例子中是 odom)并在套接字上重新传输部分消息。我已经实现了这样的事情:

#!/usr/bin/env python
import rospy
from std_msgs.msg import String
import socket
import sys
from nav_msgs.msg import Odometry
import struct
from time import sleep
import socket, threading


class ClientThread(threading.Thread):
    def __init__(self,clientAddress,clientsocket):
        threading.Thread.__init__(self)
        self.csocket = clientsocket
        print ("New connection added: ", clientAddress)
        rospy.init_node('serverOdom', anonymous=True)
        rospy.Subscriber('odom',Odometry, callback)
        print ("New subscriber 'severOdom' added: ")

    def run(self):
        rospy.spin()


def callback(msg):
    string=str(msg.pose.pose.position.x)+"\n"+str(msg.pose.pose.position.y)+"\n"
    try:
        ##How i can refeer to the socket??
        self.csocket.send(string.encode())
        print (string)
    except socket.error:
        print ("Error client lost")
        ##How to exit from spin()??


if __name__ == '__main__':
    LOCALHOST = "192.168.2.150"
    PORT = 5005
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((LOCALHOST, PORT))
    print("Server started")
    print("Waiting for client request..")
    while True:
        server.listen(1)
        clientsock, clientAddress = server.accept()
        newthread = ClientThread(clientAddress, clientsock)
        newthread.start()

现在我有两个问题: 第一个在回调函数里面我不能用的

self.csocket.send(string.encode())

我不知道如何将字符串发送给客户端。

第二个是如果客户端断开连接我无法退出回调函数

有什么想法吗?我是python和ros的初学者,提前谢谢

编辑: 我建立了一个解决方案。也许它并不优雅,但它确实有效。

#!/usr/bin/env python
import rospy
from std_msgs.msg import String
import socket
import sys
from nav_msgs.msg import Odometry
import struct
from time import sleep
import socket, threading


class ClientThread(threading.Thread):
    def __init__(self,clientAddress,clientsocket):
        threading.Thread.__init__(self)
        self.csocket = clientsocket
        print ("New connection added: ", clientAddress)
        rospy.init_node('serverOdom', anonymous=True)
        rospy.Subscriber('odom',Odometry, callback)
        print ("New subscriber 'severOdom' added: ")

    def run(self):
        while True:
            msg = rospy.wait_for_message("odom", Odometry, timeout=None)
            string=str(msg.pose.pose.position.x)+"\n"+str(msg.pose.pose.position.y)+"\n"
            try:
                self.csocket.send(string.encode())
            except socket.error:
                print ("Error client lost", clientAddress)
                return

def callback(msg):
    pass


if __name__ == '__main__':
    LOCALHOST = ""
    PORT = 5005
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((LOCALHOST, PORT))
    print("Server started")
    print("Waiting for client request..")
    while True:
        sleep(2)
        server.listen(5)
        clientsock, clientAddress = server.accept()
        newthread = ClientThread(clientAddress, clientsock)
        newthread.start()

我需要更多的客户端来连接,当与客户端的连接丢失(例如因为客户端关闭)时,服务器创建的线程结束。 使用我为服务器创建的每个线程的解决方案还创建了一个订阅者,可能最好为所有创建的线程使用单个订阅者,但现在我还不能这样做。

【问题讨论】:

    标签: python sockets ros


    【解决方案1】:

    如果将回调定义为 ClientThread 的成员,则可以访问 self.例

    class ClientThread(...):
        def callback(self, msg):
            self.csocket.send(string.encode())
    

    此外,您的控制流程很不稳定。节点的所有初始化都应该发生在 main 中;这就是你困惑的原因。例如python node

    另外,您的代码不太有意义,因为它似乎既是服务器又是客户端。前任。这是一个轻量级的重写,但它并没有真正的意义并且行为不正确。 (除了ros部分应该是正确的)。就像,您似乎正在尝试使用线程...来完成 ros 的工作,其中每个节点 就像 已经是一个线程。

    # server_odom.py
    
    # Ros imports
    import rospy
    from std_msgs.msg import String
    from nav_msgs.msg import Ododmetry
    
    # Sys imports
    import sys
    import socket
    import struct
    import threading
    from time import sleep
    
    class ClientThread(threading.Thread):
        def __init__(self,clientAddress,clientsocket):
            threading.Thread.__init__(self)
            self.csocket = clientsocket
            print ("New connection added: ", clientAddress)
            rospy.init_node('serverOdom', anonymous=True)
            rospy.Subscriber('odom',Odometry, self.callback)
            print ("New subscriber 'severOdom' added: ")
    
        def run(self):
            rospy.spin()
    
        def callback(self, msg):
            string=str(msg.pose.pose.position.x)+"\n"+str(msg.pose.pose.position.y)+"\n"
            try:
                self.csocket.send(string.encode())
                print (string)
            except socket.error:
                print ("Error client lost")
                return
    
    if __name__ == '__main__':
        LOCALHOST = ""
        PORT = 5005
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((LOCALHOST, PORT))
        print("Server started")
        print("Waiting for client request..")
        while True:
            sleep(2)
            server.listen(5)
            clientsock, clientAddress = server.accept()
            newthread = ClientThread(clientAddress, clientsock)
            newthread.start()
    

    如果您只是想将里程计消息格式化为字符串或串行缓冲区,那么代码会大大减少。

    # server_odom_min.py
    
    # Ros imports
    import rospy
    from std_msgs.msg import String
    from nav_msgs.msg import Ododmetry
    
    str_pub = None
    
    def callback(self, msg):
        s = String()
        s.data = str(msg.pose.pose.position.x)+"\n"+str(msg.pose.pose.position.y)+"\n"
        if str_pub:
            str_pub.publish(s)
    
    if __name__ == '__main__':
        rospy.init_node('server_odom_min')
        rospy.Subscriber('odom', Odometry, callback)
        str_pub = rospy.Publisher('odom/string', String, queue_size = 1)
        rospy.spin()
    

    编辑(响应编辑): 我知道你现在在做什么,我的错;第二个例子并不真正适用于这个问题。我编辑了我的第一个示例以反映您的意思。

    【讨论】:

    • 我编辑了我的问题。我还将尝试使用回调作为成员函数。感谢您的建议
    • 我编辑了我的答案作为回应:我明白你现在的意思了。但是你不需要做一个无限循环来接收ros消息,这就是Subscriber()rospy.spin()的意义所在。
    猜你喜欢
    • 2021-07-28
    • 1970-01-01
    • 2020-10-29
    • 2016-02-07
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多