Skip to content

Commit 3059b6f

Browse files
committed
2 parents 62b5723 + b02f249 commit 3059b6f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+801
-645
lines changed

examples/VPython.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
import roboticstoolbox as rp
7-
import time
7+
# import time
88

99
env = rp.backend.VPython()
1010
env.launch()

roboticstoolbox/backend/Dynamixel/dynamixel_sdk/protocol1_packet_handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def txPacket(self, port, txpacket):
130130
def rxPacket(self, port):
131131
rxpacket = []
132132

133-
result = COMM_TX_FAIL
133+
result = COMM_TX_FAIL # lgtm [py/multiple-definition]
134134
checksum = 0
135135
rx_length = 0
136136
wait_length = 6 # minimum length (HEADER0 HEADER1 ID LENGTH ERROR CHKSUM)
@@ -310,7 +310,7 @@ def readTx(self, port, dxl_id, address, length):
310310
return result
311311

312312
def readRx(self, port, dxl_id, length):
313-
result = COMM_TX_FAIL
313+
result = COMM_TX_FAIL # lgtm [py/multiple-definition]
314314
error = 0
315315

316316
rxpacket = None

roboticstoolbox/backend/Dynamixel/dynamixel_sdk/protocol2_packet_handler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def txPacket(self, port, txpacket):
249249
def rxPacket(self, port):
250250
rxpacket = []
251251

252-
result = COMM_TX_FAIL
252+
result = COMM_TX_FAIL # lgtm [py/multiple-definition]
253253
rx_length = 0
254254
wait_length = 11 # minimum length (HEADER0 HEADER1 HEADER2 RESERVED ID LENGTH_L LENGTH_H INST ERROR CRC16_L CRC16_H)
255255

@@ -438,7 +438,7 @@ def broadcastPing(self, port):
438438
return data_list, result
439439

440440
else:
441-
result = COMM_RX_CORRUPT
441+
result = COMM_RX_CORRUPT # lgtm [py/multiple-definition]
442442

443443
# remove header (0xFF 0xFF 0xFD)
444444
del rxpacket[0: 3]
@@ -450,7 +450,7 @@ def broadcastPing(self, port):
450450
rx_length = rx_length - idx
451451

452452
# FIXME: unreachable code
453-
return data_list, result
453+
return data_list, result # lgtm [py/unreachable-statement]
454454

455455
def action(self, port, dxl_id):
456456
txpacket = [0] * 10
@@ -526,7 +526,7 @@ def readTx(self, port, dxl_id, address, length):
526526
return result
527527

528528
def readRx(self, port, dxl_id, length):
529-
result = COMM_TX_FAIL
529+
result = COMM_TX_FAIL # lgtm [py/multiple-definition]
530530
error = 0
531531

532532
rxpacket = None

roboticstoolbox/backend/VPython/VPython.py

Lines changed: 96 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,51 @@
33
@author Micah Huth
44
"""
55

6+
import importlib
67
from roboticstoolbox.backend.Connector import Connector
7-
88
from roboticstoolbox.robot.DHLink import DHLink
99
from roboticstoolbox.robot.Robot import Robot as r
1010

11-
from roboticstoolbox.backend.VPython.canvas import GraphicsCanvas3D, \
12-
GraphicsCanvas2D
13-
from roboticstoolbox.backend.VPython.graphicalrobot import \
14-
GraphicalRobot
15-
from roboticstoolbox.backend.VPython.common_functions import \
16-
close_localhost_session
11+
GraphicsCanvas3D = None
12+
GraphicsCanvas2D = None
13+
GraphicalRobot = None
14+
close_localhost_session = None
15+
16+
17+
def _imports():
18+
global GraphicsCanvas3D
19+
global GraphicsCanvas2D
20+
global GraphicalRobot
21+
global close_localhost_session
22+
23+
try:
24+
canvas = importlib.import_module(
25+
'roboticstoolbox.backend.VPython.canvas')
26+
GraphicsCanvas3D = canvas.GraphicsCanvas3D
27+
GraphicsCanvas2D = canvas.GraphicsCanvas2D
28+
29+
graphicalrobot = importlib.import_module(
30+
'roboticstoolbox.backend.VPython.graphicalrobot')
31+
GraphicalRobot = graphicalrobot.GraphicalRobot
32+
33+
common_functions = importlib.import_module(
34+
'roboticstoolbox.backend.VPython.common_functions')
35+
close_localhost_session = common_functions.close_localhost_session
36+
37+
except ImportError:
38+
print(
39+
'\nYou must install the VPython component of the toolbox, do: \n'
40+
'pip install roboticstoolbox[vpython]\n\n')
1741

1842

19-
class VPython(Connector):
43+
class VPython(Connector): # pragma nocover
2044
"""
2145
Graphical backend using VPython
2246
2347
VPython is a Python API that connects to a JavaScript/WebGL 3D graphics
24-
engine in a browser tab. It supports many 3D graphical primitives including
25-
meshes, boxes, ellipsoids and lines. It can not render in full color.
48+
engine in a browser tab. It supports many 3D graphical primitives
49+
including meshes, boxes, ellipsoids and lines. It can not render in
50+
full color.
2651
2752
Example:
2853
@@ -41,7 +66,7 @@ class VPython(Connector):
4166
:references:
4267
4368
- https://vpython.org
44-
69+
4570
"""
4671
# TODO be able to add ellipsoids (vellipse, fellipse)
4772
# TODO be able add lines (for end-effector paths)
@@ -53,14 +78,19 @@ def __init__(self):
5378
"""
5479
super(VPython, self).__init__()
5580

81+
_imports()
82+
5683
# Init vars
5784
self.canvases = []
58-
self.canvas_settings = [] # 2D array of [is_3d, height, width, title, caption, grid] per canvas
85+
# 2D array of [is_3d, height, width, title, caption, grid] per canvas
86+
self.canvas_settings = []
5987
self.robots = []
6088

6189
self._create_empty_session()
6290

63-
def launch(self, is_3d=True, height=500, width=888, title='', caption='', grid=True):
91+
def launch(
92+
self, is_3d=True, height=500, width=888,
93+
title='', caption='', grid=True):
6494
"""
6595
Launch a graphical backend in a browser tab
6696
@@ -71,13 +101,16 @@ def launch(self, is_3d=True, height=500, width=888, title='', caption='', grid=T
71101

72102
super().launch()
73103

74-
self.canvas_settings.append([is_3d, height, width, title, caption, grid])
104+
self.canvas_settings.append(
105+
[is_3d, height, width, title, caption, grid])
75106

76107
# Create the canvas with the given information
77108
if is_3d:
78-
self.canvases.append(GraphicsCanvas3D(height, width, title, caption, grid))
109+
self.canvases.append(
110+
GraphicsCanvas3D(height, width, title, caption, grid))
79111
else:
80-
self.canvases.append(GraphicsCanvas2D(height, width, title, caption, grid))
112+
self.canvases.append(
113+
GraphicsCanvas2D(height, width, title, caption, grid))
81114

82115
def step(self, id, q=None, fig_num=0):
83116
"""
@@ -88,41 +121,44 @@ def step(self, id, q=None, fig_num=0):
88121
:type id: :class:`~roboticstoolbox.robot.DHRobot.DHRobot`,
89122
:class:`roboticstoolbox.backend.VPython.graphics_robot.GraphicalRobot`
90123
:param q: The joint angles/configuration of the robot (Optional, if not
91-
supplied will use the stored q values).
92-
:type q: float ndarray(n)
93-
:param fig_num: The canvas index to delete the robot from, defaults to the
94-
initial one
95-
:type fig_num: int, optional
124+
supplied will use the stored q values).
125+
:type q: float ndarray(n)
126+
:param fig_num: The canvas index to delete the robot from, defaults to
127+
the initial one
128+
:type fig_num: int, optional
96129
:raises ValueError: Figure number must be between 0 and total number of
97-
canvases
130+
canvases
98131
:raises TypeError: Input must be a DHLink or GraphicalRobot
99132
100133
``env.step(args)`` triggers an update of the 3D scene in the browser
101134
window referenced by ``env``.
102135
103-
.. note::
136+
.. note::
104137
105138
- Each robot in the scene is updated based on
106139
their control type (position, velocity, acceleration, or torque).
107140
- Upon acting, the other three of the four control types will be
108-
updated in the internal state of the robot object.
109-
- The control type is defined by the robot object, and not all robot
110-
objects support all control types.
141+
updated in the internal state of the robot object.
142+
- The control type is defined by the robot object, and not all
143+
robot objects support all control types.
111144
- Execution is blocked for the specified interval
112145
113146
"""
114147

115148
super().step()
116149

117150
if fig_num < 0 or fig_num >= len(self.canvases):
118-
raise ValueError("Figure number must be between 0 and total number of canvases")
151+
raise ValueError(
152+
"Figure number must be between 0 and total number of canvases")
119153

120154
# If DHRobot given
121155
if isinstance(id, r.Robot):
122156
robot = None
123157
# Find first occurrence of it that is in the correct canvas
124158
for i in range(len(self.robots)):
125-
if self.robots[i].robot is id and self.canvases[fig_num].is_robot_in_canvas(self.robots[i]):
159+
if self.robots[i].robot is id and \
160+
self.canvases[fig_num].is_robot_in_canvas(
161+
self.robots[i]):
126162
robot = self.robots[i]
127163
break
128164
if robot is None:
@@ -138,7 +174,9 @@ def step(self, id, q=None, fig_num=0):
138174
id.set_joint_poses(poses)
139175
# Else
140176
else:
141-
raise TypeError("Input must be a Robot (or subclass) or GraphicalRobot, given {0}".format(type(id)))
177+
raise TypeError(
178+
"Input must be a Robot (or subclass) or "
179+
"GraphicalRobot, given {0}".format(type(id)))
142180

143181
def reset(self):
144182
"""
@@ -168,9 +206,13 @@ def reset(self):
168206
for settings in self.canvas_settings:
169207
# Create the canvas with the given information
170208
if settings[0]:
171-
self.canvases.append(GraphicsCanvas3D(settings[1], settings[2], settings[3], settings[4], settings[5]))
209+
self.canvases.append(GraphicsCanvas3D(
210+
settings[1], settings[2], settings[3],
211+
settings[4], settings[5]))
172212
else:
173-
self.canvases.append(GraphicsCanvas2D(settings[1], settings[2], settings[3], settings[4], settings[5]))
213+
self.canvases.append(GraphicsCanvas2D(
214+
settings[1], settings[2], settings[3],
215+
settings[4], settings[5]))
174216

175217
def restart(self):
176218
"""
@@ -184,16 +226,6 @@ def restart(self):
184226

185227
super().restart()
186228

187-
# self.close()
188-
# self._create_empty_session()
189-
# for settings in self.canvas_settings:
190-
# # Create the canvas with the given information
191-
# if settings[0]:
192-
# self.canvases.append(GraphicsCanvas3D(settings[1], settings[2], settings[3], settings[4], settings[5]))
193-
# else:
194-
# self.canvases.append(GraphicsCanvas2D(settings[1], settings[2], settings[3], settings[4], settings[5]))
195-
196-
# Program on close terminates execution, so just run reset
197229
self.reset()
198230

199231
def close(self):
@@ -222,21 +254,23 @@ def add(self, fig_num, name, dhrobot):
222254
"""
223255
Add a robot to the graphical scene
224256
225-
:param fig_num: The canvas number to place the robot in
257+
:param fig_num: The canvas number to place the robot in
226258
:type fig_num: int
227-
:param name: The name of the robot
228-
:type name: `str`
229-
:param dhrobot: The ``DHRobot`` object (if applicable)
230-
:type dhrobot: class:`~roboticstoolbox.robot.DHRobot.DHRobot`, None
231-
:raises ValueError: Figure number must be between 0 and number of figures created
259+
:param name: The name of the robot
260+
:type name: `str`
261+
:param dhrobot: The ``DHRobot`` object (if applicable)
262+
:type dhrobot: class:`~roboticstoolbox.robot.DHRobot.DHRobot`, None
263+
:raises ValueError: Figure number must be between 0 and number of
264+
figures created
232265
:return: object id within visualizer
233266
:rtype: int
234267
235-
``id = env.add(robot)`` adds the ``robot`` to the graphical environment.
268+
``id = env.add(robot)`` adds the ``robot`` to the graphical
269+
environment.
236270
237271
.. note::
238272
239-
- ``robot`` must be of an appropriate class.
273+
- ``robot`` must be of an appropriate class.
240274
- Adds the robot object to a list of robots which will be updated
241275
when the ``step()`` method is called.
242276
@@ -251,42 +285,48 @@ def add(self, fig_num, name, dhrobot):
251285

252286
# Sanity check input
253287
if fig_num < 0 or fig_num > len(self.canvases) - 1:
254-
raise ValueError("Figure number must be between 0 and number of figures created")
288+
raise ValueError(
289+
"Figure number must be between 0 and number "
290+
"of figures created")
255291

256292
# Add robot to canvas
257-
self.robots.append(GraphicalRobot(self.canvases[fig_num], name, dhrobot))
293+
self.robots.append(
294+
GraphicalRobot(self.canvases[fig_num], name, dhrobot))
258295
# self.canvases[fig_num].add_robot(self.robots[len(self.robots)-1])
259296

260297
def remove(self, id, fig_num=0):
261298
"""
262299
Remove a robot to the graphical scene
263300
264-
:param id: The id of the robot to remove. Can be either the DHLink or
301+
:param id: The id of the robot to remove. Can be either the DHLink or
265302
GraphicalRobot
266303
:type id: class:`~roboticstoolbox.robot.DHRobot.DHRobot`,
267304
class:`roboticstoolbox.backend.VPython.graphics_robot.GraphicalRobot`
268305
:param fig_num: The canvas index to delete the robot from, defaults to
269306
the initial one
270307
:type fig_num: int, optional
271-
:raises ValueError: Figure number must be between 0 and total number
308+
:raises ValueError: Figure number must be between 0 and total number
272309
of canvases
273310
:raises TypeError: Input must be a DHLink or GraphicalRobot
274311
275-
``env.remove(robot)`` removes the ``robot`` from the graphical environment.
312+
``env.remove(robot)`` removes the ``robot`` from the graphical
313+
environment.
276314
277315
"""
278316

279317
super().remove()
280318

281319
if fig_num < 0 or fig_num >= len(self.canvases):
282-
raise ValueError("Figure number must be between 0 and total number of canvases")
320+
raise ValueError(
321+
"Figure number must be between 0 and total number of canvases")
283322

284323
# If DHLink given
285324
if isinstance(id, DHLink):
286325
robot = None
287326
# Find first occurrence of it that is in the correct canvas
288327
for i in range(len(self.robots)):
289-
if self.robots[i].seriallink.equal(id) and self.canvases[fig_num].is_robot_in(self.robots[i]):
328+
if self.robots[i].seriallink.equal(id) and \
329+
self.canvases[fig_num].is_robot_in(self.robots[i]):
290330
robot = self.robots[i]
291331
break
292332
if robot is None:

0 commit comments

Comments
 (0)