3
3
@author Jesse Haviland
4
4
"""
5
5
6
- import os
7
6
from subprocess import call , Popen
8
7
from roboticstoolbox .backend .Connector import Connector
9
- import zerorpc
10
8
import roboticstoolbox as rp
11
9
import numpy as np
12
10
import spatialmath as sm
13
11
import time
12
+ import websockets
13
+ import asyncio
14
+ from threading import Thread
15
+ from queue import Queue , Empty
16
+ import webbrowser as wb
17
+ import json
18
+ import http .server
19
+ import socketserver
20
+ from pathlib import Path
21
+ import os
14
22
15
23
16
24
class Swift (Connector ): # pragma nocover
@@ -43,7 +51,10 @@ class Swift(Connector): # pragma nocover
43
51
def __init__ (self ):
44
52
super (Swift , self ).__init__ ()
45
53
46
- # Popen(['npm', 'start', '--prefix', os.environ['SIM_ROOT']])
54
+ self .robots = []
55
+ self .shapes = []
56
+ self .outq = Queue ()
57
+ self .inq = Queue ()
47
58
48
59
#
49
60
# Basic methods to do with the state of the external program
@@ -60,11 +71,40 @@ def launch(self):
60
71
61
72
super ().launch ()
62
73
63
- self .robots = []
64
- self .shapes = []
65
-
66
- self .swift = zerorpc .Client ()
67
- self .swift .connect ("tcp://127.0.0.1:4242" )
74
+ # Start a http server
75
+ self .server = Thread (
76
+ target = Server , args = (self .inq , ), daemon = True )
77
+ self .server .start ()
78
+ http_port = self .inq .get ()
79
+
80
+ # Start our websocket server with a new clean port
81
+ self .socket = Thread (
82
+ target = Socket , args = (self .outq , self .inq , ), daemon = True )
83
+ self .socket .start ()
84
+ port = self .inq .get ()
85
+
86
+ # Launch the simulator
87
+ wb .open_new_tab ('http://localhost:' + str (http_port ))
88
+ # wb.open_new_tab('file:///home/jesse/swift/public/index.html')
89
+
90
+ # Let swift know which port to talk on using the common port
91
+ loop = asyncio .new_event_loop ()
92
+
93
+ async def send_port (websocket , path ):
94
+ await websocket .send (str (port ))
95
+ await websocket .wait_closed ()
96
+ loop .stop ()
97
+
98
+ asyncio .set_event_loop (loop )
99
+ port_ws = websockets .serve (send_port , "localhost" , 8997 )
100
+ loop .run_until_complete (port_ws )
101
+ loop .run_forever ()
102
+
103
+ try :
104
+ self .inq .get (timeout = 10 )
105
+ except Empty :
106
+ print ('\n Could not connect to the Swift simulator \n ' )
107
+ raise
68
108
69
109
def step (self , dt = 50 ):
70
110
"""
@@ -81,9 +121,9 @@ def step(self, dt=50):
81
121
- Each robot in the scene is updated based on
82
122
their control type (position, velocity, acceleration, or torque).
83
123
- Upon acting, the other three of the four control types will be
84
- updated in the internal state of the robot object.
85
- - The control type is defined by the robot object, and not all robot
86
- objects support all control types.
124
+ updated in the internal state of the robot object.
125
+ - The control type is defined by the robot object, and not all
126
+ robot objects support all control types.
87
127
- Execution is blocked for the specified interval
88
128
89
129
"""
@@ -149,7 +189,8 @@ def add(self, ob, show_robot=True, show_collision=False):
149
189
:return: object id within visualizer
150
190
:rtype: int
151
191
152
- ``id = env.add(robot)`` adds the ``robot`` to the graphical environment.
192
+ ``id = env.add(robot)`` adds the ``robot`` to the graphical
193
+ environment.
153
194
154
195
.. note::
155
196
@@ -169,20 +210,21 @@ def add(self, ob, show_robot=True, show_collision=False):
169
210
robot = ob .to_dict ()
170
211
robot ['show_robot' ] = show_robot
171
212
robot ['show_collision' ] = show_collision
172
- id = self .swift . robot ( robot )
213
+ id = self ._send_socket ( 'robot' , robot )
173
214
174
215
loaded = False
175
216
while not loaded :
176
- loaded = self .swift . is_loaded ( id )
217
+ loaded = self ._send_socket ( 'is_loaded' , id )
177
218
time .sleep (0.1 )
178
219
179
220
self .robots .append (ob )
180
221
return id
181
- elif isinstance (ob , rp .Shape ):
182
- shape = ob .to_dict ()
183
- id = self .swift .shape (shape )
184
- self .shapes .append (ob )
185
- return id
222
+ # elif isinstance(ob, rp.Shape):
223
+ # shape = ob.to_dict()
224
+ # id = self.swift.shape(shape)
225
+ # id = self._send_socket('shape', shape)
226
+ # self.shapes.append(ob)
227
+ # return id
186
228
187
229
def remove (self ):
188
230
"""
@@ -239,13 +281,108 @@ def _draw_all(self):
239
281
240
282
for i in range (len (self .robots )):
241
283
self .robots [i ].fkine_all ()
242
- self .swift .robot_poses ([i , self .robots [i ].fk_dict ()])
284
+ # self.swift.robot_poses([i, self.robots[i].fk_dict()])
285
+ self ._send_socket ('robot_poses' , [i , self .robots [i ].fk_dict ()])
243
286
244
287
for i in range (len (self .shapes )):
245
- self .swift .shape_poses ([i , self .shapes [i ].fk_dict ()])
288
+ # self.swift.shape_poses([i, self.shapes[i].fk_dict()])
289
+ self ._send_socket ('shape_poses' , [i , self .shapes [i ].fk_dict ()])
290
+
291
+ # def record_start(self, file):
292
+ # self.swift.record_start(file)
293
+
294
+ # def record_stop(self):
295
+ # self.swift.record_stop(1)
296
+
297
+ def _send_socket (self , code , data ):
298
+ msg = [code , data ]
299
+
300
+ self .outq .put (msg )
301
+ return self .inq .get ()
302
+
303
+
304
+ class Socket :
305
+
306
+ def __init__ (self , outq , inq ):
307
+ self .outq = outq
308
+ self .inq = inq
309
+ self .USERS = set ()
310
+ loop = asyncio .new_event_loop ()
311
+ asyncio .set_event_loop (loop )
312
+
313
+ started = False
314
+ port = 51478
315
+
316
+ while not started and port < 62000 :
317
+ try :
318
+ port += 1
319
+ start_server = websockets .serve (self .serve , "localhost" , port )
320
+ loop .run_until_complete (start_server )
321
+ started = True
322
+ except OSError :
323
+ pass
324
+
325
+ self .inq .put (port )
326
+ loop .run_forever ()
327
+
328
+ async def register (self , websocket ):
329
+ self .USERS .add (websocket )
330
+
331
+ async def serve (self , websocket , path ):
332
+
333
+ # Initial connection handshake
334
+ await (self .register (websocket ))
335
+ recieved = await websocket .recv ()
336
+ self .inq .put (recieved )
337
+
338
+ # Now onto send, recieve cycle
339
+ while True :
340
+ message = await self .producer ()
341
+ await websocket .send (json .dumps (message ))
342
+
343
+ recieved = await websocket .recv ()
344
+ self .inq .put (recieved )
345
+ print (recieved )
346
+
347
+ async def producer (self ):
348
+ data = self .outq .get ()
349
+ return data
350
+
351
+
352
+ class Server :
353
+
354
+ def __init__ (self , inq ):
355
+
356
+ PORT = 52000
357
+ self .inq = inq
358
+
359
+ root_dir = Path (rp .__file__ ).parent / 'public'
360
+ os .chdir (Path .home ())
361
+
362
+ class MyHttpRequestHandler (http .server .SimpleHTTPRequestHandler ):
363
+ def do_GET (self ):
364
+
365
+ home = str (Path .home ())
366
+
367
+ if self .path == '/' :
368
+ self .path = str (root_dir / 'index.html' )
369
+ elif self .path .endswith ('css' ) or self .path .endswith ('js' ):
370
+ self .path = str (root_dir ) + self .path
371
+
372
+ if self .path .startswith (home ):
373
+ self .path = self .path [len (home ):]
374
+
375
+ return http .server .SimpleHTTPRequestHandler .do_GET (self )
376
+
377
+ Handler = MyHttpRequestHandler
246
378
247
- def record_start (self , file ):
248
- self .swift .record_start (file )
379
+ connected = False
249
380
250
- def record_stop (self ):
251
- self .swift .record_stop (1 )
381
+ while not connected and PORT < 62000 :
382
+ try :
383
+ with socketserver .TCPServer (("" , PORT ), Handler ) as httpd :
384
+ self .inq .put (PORT )
385
+ connected = True
386
+ httpd .serve_forever ()
387
+ except OSError :
388
+ PORT += 1
0 commit comments