# 二. 基本操作

# 1. ros与无法进行ros连接的软件通信

将websocts的发送函数作为ros订阅的回调。

例如,ros在与打包成webgl的unity模型进行通信时,可以将发送消息的函数放入订阅消息的回调函数之中。

#!/usr/bin/env python
import threading
import rospy
from std_msgs.msg import String

import tornado
from tornado import websocket

write_func = None
port = 7070

class EchoWebSocket(websocket.WebSocketHandler):
    def open(self):
        global write_func
        write_func = self.write_message
        rospy.loginfo("New client connected")
        
    def on_message(self, message):
        pass
    
    def on_close(self):
        global write_func
        write_func = None
        self.loop.stop()
        rospy.loginfo("Connection is closed")
    
    def check_origin(self, origin):
        return True

def callback(data):
    # rospy.loginfo("Sub data: %s", str(data.data))

    global write_func
    if write_func:
        # write_func(data.data, binary=True)
        write_func(data.data.decode('hex'), binary=True)
        rospy.loginfo("ws2unity data: %s", str(data.data))
        

    
def ros_listener():
    # In ROS, nodes are uniquely named. If two nodes with the same
    # name are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('model_ctl_server', anonymous=True)

    rospy.Subscriber("/crane_cmd/hex_cmd", String, callback)

    ros_thread = threading.Thread(target = ros_spin)
    ros_thread.start()
    

def ros_spin():
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

def ws_server():
    global port
    app = tornado.web.Application([
        (r'/', EchoWebSocket),
    ])
    app.listen(port)
    tornado.ioloop.IOLoop.current().start()

if __name__ == '__main__':
    ros_listener()
    
    ws_thread = threading.Thread(target = ws_server)
    ws_thread.start()

其中的write_func即为发送消息函数的全局变量。