繁体   English   中英

python 中套接字的 ROS 订阅者

[英]ROS subscriber to socket in python

大家好,我想实现一个 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()

现在我有两个问题:第一个在回调 function 中我无法使用

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

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

第二个是如果客户端断开我不能退出回调 function

一些想法? 我是 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()

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

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

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

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

此外,您的代码不太有意义,因为它似乎既是服务器又是客户端。 前任。 这是一个轻微的重写,但它并没有真正意义并且不会表现正确。 (除了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()

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM