00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 import os
00018 import json
00019 import rospy
00020
00021
00022 from include.logger import Log
00023 from include.constants import DEFAULT_QUEUE_SIZE, DEFAULT_CONTEXT_TYPE, SEPARATOR_CHAR, IP, MAP_SERVER_PORT, ROSBRIDGE_PORT
00024 from include.libLoader import LibLoader
00025
00026 from include.ros.rosConfigurator import RosConfigurator
00027 from include.ros.rosutils import ros2Obj, obj2Ros, ros2Definition
00028 from include.ros.dependencies.third_party import *
00029
00030
00031 from include.pubsub.pubSubFactory import PublisherFactory, SubscriberFactory
00032
00033 import std_msgs.msg
00034
00035 CloudSubscriber = SubscriberFactory.create()
00036 CloudPublisher = PublisherFactory.create()
00037
00038
00039 TOPIC_BASE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "topics")
00040 ROBOT_TOPICS = {}
00041 robot_data = {}
00042 subscribers = []
00043
00044
00045 def loadMsgHandlers(robot_data):
00046
00047
00048 Log("INFO", "Getting configuration data")
00049 Log("INFO", "Generating topic handlers:")
00050 msg_types = {}
00051 for robotName in robot_data:
00052 robotName = str(robotName)
00053 robot = robot_data[robotName]
00054 if robotName not in ROBOT_TOPICS:
00055 ROBOT_TOPICS[robotName] = {
00056 "publisher": {},
00057 "subscriber": {}
00058 }
00059 Log("INFO", " -" + robotName)
00060 for topicName in robot['topics']:
00061 topic = robot['topics'][topicName]
00062 topicName = str(topicName)
00063 Log("INFO", " -" + topicName)
00064 extra = {"robot": robotName, "topic": topicName}
00065 if type(topic['msg']) is dict:
00066 _topic_name = robotName + ".msg." + topicName
00067 module = LibLoader.loadFromFile(os.path.join(TOPIC_BASE_PATH, robotName+topicName+".py"))
00068 theclass = getattr(module, topicName)
00069 else:
00070 _final_name = topic['msg'].split('.')[-1]
00071 _topic_name = str(topic['msg'])
00072 if _final_name in globals():
00073 theclass = globals()[_final_name]
00074 else:
00075 theclass = LibLoader.loadFromSystem(topic['msg'])
00076 extra["type"] = _topic_name
00077
00078 msg_types[_topic_name] = {
00079 "name": _topic_name,
00080 "type": "rosmsg",
00081 "value": json.dumps(ros2Definition(theclass())).replace('"', SEPARATOR_CHAR)
00082 }
00083
00084 if topic["type"].lower() == "publisher":
00085 ROBOT_TOPICS[robotName]["publisher"][topicName] = {
00086 "msg": str(topic['msg']),
00087 "class": theclass,
00088 "publisher": rospy.Publisher(robotName + "/" + topicName, theclass, queue_size=DEFAULT_QUEUE_SIZE)
00089 }
00090 elif topic["type"].lower() == "subscriber":
00091 ROBOT_TOPICS[robotName]["subscriber"][topicName] = {
00092 "msg": str(topic['msg']),
00093 "class": theclass,
00094 "subscriber": rospy.Subscriber(robotName + "/" + topicName, theclass, _callback, extra)
00095 }
00096 Log("INFO", "\n")
00097 CloudSubscriber.subscribe(robotName, DEFAULT_CONTEXT_TYPE, ROBOT_TOPICS[robotName])
00098 Log("INFO", "Subscribed to " + robotName + "'s topics\n")
00099 CloudPublisher.publishMsg(msg_types.values())
00100 MapHandler.mapPublisher()
00101
00102
00103 def connectionListeners():
00104
00105 subscribers.append(rospy.Subscriber("firos/disconnect", std_msgs.msg.String, robotDisconnection))
00106 subscribers.append(rospy.Subscriber("firos/connect", std_msgs.msg.String, _robotConnection))
00107
00108
00109 class MapHandler:
00110 @staticmethod
00111 def mapPublisher():
00112
00113 maps = RosConfigurator.getMapTopics()
00114 cb_maps = [
00115 {
00116 "name": "websocket",
00117 "type": "connection",
00118 "value": "ws://{}:{}".format(IP, ROSBRIDGE_PORT)
00119 }
00120 ]
00121 if(MAP_SERVER_PORT):
00122 cb_maps.append({
00123 "name": "socketio",
00124 "type": "connection",
00125 "value": "http://{}:{}".format(IP, MAP_SERVER_PORT)
00126 })
00127 for map_topic in maps:
00128 CloudPublisher.publishMap(map_topic, cb_maps)
00129
00130 @staticmethod
00131 def mapRemover():
00132
00133 maps = RosConfigurator.getMapTopics()
00134 for map_topic in maps:
00135 CloudSubscriber.deleteEntity(map_topic, "MAP", False)
00136
00137
00138 class TopicHandler:
00139 @staticmethod
00140 def publish(robot, topic, data):
00141
00142
00143
00144
00145 if robot in ROBOT_TOPICS and topic in ROBOT_TOPICS[robot]["publisher"]:
00146 instance = ROBOT_TOPICS[robot]["publisher"][topic]
00147 msg = instance["class"]()
00148 obj2Ros(data, msg)
00149 if "publisher" in instance:
00150 instance["publisher"].publish(msg)
00151
00152 @staticmethod
00153 def unregisterAll():
00154
00155 CloudSubscriber.disconnectAll()
00156 MapHandler.mapRemover()
00157 Log("INFO", "Unsubscribing topics...")
00158 for subscriber in subscribers:
00159 subscriber.unregister()
00160 for robot_name in ROBOT_TOPICS:
00161 for topic in ROBOT_TOPICS[robot_name]["subscriber"]:
00162 ROBOT_TOPICS[robot_name]["subscriber"][topic]["subscriber"].unregister()
00163 Log("INFO", "Unsubscribed topics\n")
00164
00165
00166 def _callback(data, args):
00167
00168
00169
00170 robot = str(args['robot'])
00171 topic = str(args['topic'])
00172 datatype = ROBOT_TOPICS[robot]["subscriber"][topic]["msg"]
00173 contextType = DEFAULT_CONTEXT_TYPE
00174 content = []
00175 content.append(CloudPublisher.createContent(topic, datatype, ros2Obj(data)))
00176 CloudPublisher.publish(robot, contextType, content)
00177
00178
00179 def robotDisconnection(data):
00180
00181
00182 robot_name = data.data
00183 Log("INFO", "Disconnected robot: " + robot_name)
00184 if robot_name in ROBOT_TOPICS:
00185 CloudSubscriber.deleteEntity(robot_name, DEFAULT_CONTEXT_TYPE)
00186 CloudSubscriber.disconnect(robot_name, True)
00187 for topic in ROBOT_TOPICS[robot_name]["publisher"]:
00188 ROBOT_TOPICS[robot_name]["publisher"][topic]["publisher"].unregister()
00189 for topic in ROBOT_TOPICS[robot_name]["subscriber"]:
00190 ROBOT_TOPICS[robot_name]["subscriber"][topic]["subscriber"].unregister()
00191 RosConfigurator.removeRobot(robot_name)
00192
00193
00194 def _robotConnection(data):
00195
00196
00197 robot_name = data.data
00198 Log("INFO", "Connected robot: " + robot_name)
00199 loadMsgHandlers(RosConfigurator.systemTopics(True))