topicHandler.py
Go to the documentation of this file.
00001 # MIT License
00002 #
00003 # Copyright (c) <2015> <Ikergune, Etxetar>
00004 #
00005 # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
00006 # (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
00007 # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
00008 # subject to the following conditions:
00009 #
00010 # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
00011 #
00012 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00013 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
00014 # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00015 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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 # PubSub Handlers
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     ## \brief Load ROS publishers/subscribers based on robot data
00047     # \param robot data
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     ## \brief Create firos listeners for robot creation or removal
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         ## \brief Obtain map topics and publsh their link into context broker
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         ## \brief Delete map topics from context broker
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         ## \brief Publish data to ROS
00142         # \param robot name
00143         # \param topic name
00144         # \param data to publish
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         ## \brief Unregister from all ROS topics
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     ## \brief Callback to handle ROS published data and send it to Context Broker
00168     # \param data
00169     # \param extra arguments
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     ## \brief Handle robot diconnection
00181     # \param robot data dict (name)
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     ## \brief Handle robot connection
00196     # \param robot data (Not neccessary)
00197     robot_name = data.data
00198     Log("INFO", "Connected robot: " + robot_name)
00199     loadMsgHandlers(RosConfigurator.systemTopics(True))


firos
Author(s): IƱigo Gonzalez, igonzalez@ikergune.com
autogenerated on Thu Jun 6 2019 17:51:04