00001 import websocket
00002 import thread
00003
00004 import json
00005 import traceback
00006 import time
00007
00008 import string
00009 import random
00010
00011
00012 class RosbridgeSetup():
00013 def __init__(self, host, port):
00014 self.callbacks = {}
00015 self.service_callbacks = {}
00016 self.resp = None
00017 self.connection = RosbridgeWSConnection(host, port)
00018 self.connection.registerCallback(self.onMessageReceived)
00019
00020 def publish(self, topic, obj):
00021 pub = {"op": "publish", "topic": topic, "msg": obj}
00022 self.send(pub)
00023
00024 def subscribe(self, topic, callback, throttle_rate=-1):
00025 if self.addCallback(topic, callback):
00026 sub = {"op": "subscribe", "topic": topic}
00027 if throttle_rate > 0:
00028 sub['throttle_rate'] = throttle_rate
00029
00030 self.send(sub)
00031
00032 def unhook(self, callback):
00033 keys_for_deletion = []
00034 for key, values in self.callbacks.iteritems():
00035 for value in values:
00036 if callback == value:
00037 print "Found!"
00038 values.remove(value)
00039 if len(values) == 0:
00040 keys_for_deletion.append(key)
00041
00042 for key in keys_for_deletion:
00043 self.unsubscribe(key)
00044 self.callbacks.pop(key)
00045
00046 def unsubscribe(self, topic):
00047 unsub = {"op": "unsubscribe", "topic": topic}
00048 self.send(unsub)
00049
00050 def callService(self, serviceName, callback=None, msg=None):
00051 id = self.generate_id()
00052 call = {"op": "call_service", "id": id, "service": serviceName}
00053 if msg != None:
00054 call['args'] = msg
00055
00056 if callback == None:
00057 self.resp = None
00058 def internalCB(msg):
00059 self.resp = msg
00060 return None
00061
00062 self.addServiceCallback(id, internalCB)
00063 self.send(call)
00064
00065 while self.resp == None:
00066 time.sleep(0.01)
00067
00068 return self.resp
00069
00070 self.addServiceCallback(id, callback)
00071 self.send(call)
00072 return None
00073
00074 def send(self, obj):
00075 try:
00076 self.connection.sendString(json.dumps(obj))
00077 except:
00078 traceback.print_exc()
00079 raise
00080
00081 def generate_id(self, chars=16):
00082 return ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(chars))
00083
00084 def addServiceCallback(self, id, callback):
00085 self.service_callbacks[id] = callback
00086
00087 def addCallback(self, topic, callback):
00088 if self.callbacks.has_key(topic):
00089 self.callbacks[topic].append(callback)
00090 return False
00091
00092 self.callbacks[topic] = [callback]
00093 return True
00094
00095 def is_connected(self):
00096 return self.connection.connected
00097
00098 def is_errored(self):
00099 return self.connection.errored
00100
00101 def onMessageReceived(self, message):
00102 try:
00103
00104 obj = json.loads(message)
00105
00106
00107 if obj.has_key('op'):
00108 option = obj['op']
00109 if option == "publish":
00110 topic = obj["topic"]
00111 msg = obj["msg"]
00112 if self.callbacks.has_key(topic):
00113 for callback in self.callbacks[topic]:
00114 try:
00115 callback(msg)
00116 except:
00117 print "exception on callback", callback, "from", topic
00118 traceback.print_exc()
00119 raise
00120 elif option == "service_response":
00121 if obj.has_key("id"):
00122 id = obj["id"]
00123 values = obj["values"]
00124 if self.service_callbacks.has_key(id):
00125 try:
00126
00127 self.service_callbacks[id](values)
00128 except:
00129 print "exception on callback ID:", id
00130 traceback.print_exc()
00131 raise
00132 else:
00133 print "Missing ID!"
00134 else:
00135 print "Recieved unknown option - it was: ", option
00136 else:
00137 print "No OP key!"
00138 except:
00139 print "exception in onMessageReceived"
00140 print "message", message
00141 traceback.print_exc()
00142 raise
00143
00144
00145 class RosbridgeWSConnection():
00146 def __init__(self, host, port):
00147 self.ws = websocket.WebSocketApp(("ws://%s:%d/" % (host, port)), on_message=self.on_message, on_error=self.on_error, on_close=self.on_close)
00148 self.ws.on_open = self.on_open
00149 self.run_thread = thread.start_new_thread(self.run, ())
00150 self.connected = False
00151 self.errored = False
00152 self.callbacks = []
00153
00154 def on_open(self, ws):
00155 print "### ROS bridge connected ###"
00156 self.connected=True
00157
00158 def sendString(self, message):
00159 if not self.connected:
00160 print "Error: not connected, could not send message"
00161
00162 else:
00163 self.ws.send(message)
00164
00165 def on_error(self, ws, error):
00166 self.errored = True
00167 print "Error: %s" % error
00168
00169 def on_close(self, ws):
00170 self.connected = False
00171 print "### ROS bridge closed ###"
00172
00173 def run(self, *args):
00174 self.ws.run_forever()
00175
00176 def on_message(self, ws, message):
00177
00178 for callback in self.callbacks:
00179 callback(message)
00180
00181 def registerCallback(self, callback):
00182 self.callbacks.append(callback)