Skip to content

Commit 7784f4d

Browse files
committed
add options setting mechanism via passed dicts
handle prismatic joints properly
1 parent 0af4b42 commit 7784f4d

File tree

4 files changed

+127
-82
lines changed

4 files changed

+127
-82
lines changed

roboticstoolbox/backends/PyPlot/PyPlot.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,10 @@ def launch(self, name=None, fig=None, limits=None, **kwargs):
123123
self.ax.set_ylim3d([limits[2], limits[3]])
124124
self.ax.set_zlim3d([limits[4], limits[5]])
125125

126+
self.limits = limits
127+
126128
# disable the display of value under cursor
127-
self.ax.format_coord = lambda x, y: ''
129+
# self.ax.format_coord = lambda x, y: ''
128130

129131
# add time display in top-right corner
130132
self.timer = plt.figtext(0.85, 0.95, '')
@@ -235,7 +237,7 @@ def close(self):
235237

236238
def add(
237239
self, ob, readonly=False, display=True,
238-
jointaxes=True, jointlabels=False, eeframe=True, shadow=True, name=True):
240+
jointaxes=True, jointlabels=False, eeframe=True, shadow=True, name=True, options=None):
239241
"""
240242
Add a robot to the graphical scene
241243
@@ -274,8 +276,8 @@ def add(
274276
if isinstance(ob, rp.DHRobot) or isinstance(ob, rp.ERobot):
275277
self.robots.append(
276278
RobotPlot(
277-
ob, self.ax, readonly, display,
278-
jointaxes, jointlabels, eeframe, shadow, name))
279+
ob, self, readonly, display,
280+
jointaxes, jointlabels, eeframe, shadow, name, options))
279281
self.robots[len(self.robots) - 1].draw()
280282
id = len(self.robots)
281283

@@ -454,8 +456,11 @@ def text_trans(text, q): # pragma: no cover
454456

455457
# Update the self state in mpl and the text
456458
def update(val, text, robot): # pragma: no cover
457-
for i in range(robot.n):
458-
robot.q[i] = self.sjoint[i].val * np.pi/180
459+
for j in range(robot.n):
460+
if robot.isrevolute(j):
461+
robot.q[j] = np.radians(self.sjoint[j].val)
462+
else:
463+
robot.q[j] = self.sjoint[j].val
459464
text_trans(text, robot.q)
460465

461466
fig.subplots_adjust(left=0.25)
@@ -469,10 +474,7 @@ def update(val, text, robot): # pragma: no cover
469474
self.axjoint = []
470475
self.sjoint = []
471476

472-
qlim = np.copy(robot.qlim) * 180/np.pi
473-
474-
qlim[0, :] = np.where(np.isnan(qlim[0, :]), -180, qlim[0, :])
475-
qlim[1, :] = np.where(np.isnan(qlim[1, :]), 180, qlim[1, :])
477+
qlim = robot.todegrees(robot.qlim)
476478

477479
# if np.all(qlim == 0): # pragma: no cover
478480
# qlim[0, :] = -180
@@ -508,18 +510,24 @@ def update(val, text, robot): # pragma: no cover
508510
0.02, 1 - ym + 0.06, "Joint angles",
509511
fontsize=9, weight="bold", color="#4f4f4f")
510512

511-
for i in range(robot.n):
512-
ymin = (1 - ym) - i * yh
513+
for j in range(robot.n):
514+
ymin = (1 - ym) - j * yh
513515
ax = fig.add_axes([x1, ymin, x2, 0.03], facecolor='#dbdbdb')
514516
self.axjoint.append(ax)
515517

516-
self.sjoint.append(
517-
Slider(
518-
ax, 'q' + str(i),
519-
qlim[0, i], qlim[1, i], robot.q[i] * 180/np.pi))
520-
521-
self.sjoint[i].on_changed(lambda x: update(x, text, robot))
522-
518+
if robot.isrevolute(j):
519+
slider = Slider(
520+
ax, 'q' + str(j),
521+
qlim[0, j], qlim[1, j], np.degrees(q[j]), "% .1f°")
522+
else:
523+
slider = Slider(
524+
ax, 'q' + str(j),
525+
qlim[0, j], qlim[1, j], robot.q[j], "% .1f")
526+
527+
slider.on_changed(lambda x: update(x, text, robot))
528+
self.sjoint.append(slider)
529+
robot.q = q
530+
self.step()
523531

524532
def _isnotebook():
525533
"""

roboticstoolbox/backends/PyPlot/PyPlot2.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def add(
171171
if isinstance(ob, rp.ERobot2):
172172
self.robots.append(
173173
RobotPlot2(
174-
ob, self.ax, readonly, display,
174+
ob, self, readonly, display,
175175
eeframe, name))
176176
self.robots[len(self.robots) - 1].draw()
177177

@@ -187,12 +187,23 @@ def remove(self):
187187
188188
'''
189189

190-
super().remove()
190+
super().remove() # ???
191191

192192
def hold(self): # pragma: no cover
193+
'''
194+
hold() keeps the plot open i.e. stops the plot from closing once
195+
the main script has finished.
196+
197+
'''
198+
193199
# signal.setitimer(signal.ITIMER_REAL, 0)
194200
plt.ioff()
195-
plt.show()
201+
202+
# keep stepping the environment while figure is open
203+
while True:
204+
if not plt.fignum_exists(self.fig.number):
205+
break
206+
self.step()
196207

197208
#
198209
# Private methods
@@ -261,15 +272,11 @@ def text_trans(text, q): # pragma: no cover
261272
def update(val, text, robot): # pragma: no cover
262273
for j in range(robot.n):
263274
if robot.isrevolute(j):
264-
robot.q[j] = self.sjoint[j].val * np.pi / 180
275+
robot.q[j] = np.radians(self.sjoint[j].val)
265276
else:
266277
robot.q[j] = self.sjoint[j].val
267-
268278
text_trans(text, robot.q)
269279

270-
# Step the environment
271-
self.step(0)
272-
273280
fig.subplots_adjust(left=0.38)
274281
text = []
275282

@@ -321,16 +328,14 @@ def update(val, text, robot): # pragma: no cover
321328
if robot.isrevolute(j):
322329
slider = Slider(
323330
self.axjoint[j], 'q' + str(j),
324-
qlim[0, j], qlim[1, j], q[j] * 180/np.pi, "% .1f°")
331+
qlim[0, j], qlim[1, j], np.degrees(q[j]), "% .1f°")
325332
else:
326333
slider = Slider(
327334
self.axjoint[j], 'q' + str(j),
328335
qlim[0, j], qlim[1, j], q[j], "% .1f")
329336

330337
slider.on_changed(lambda x: update(x, text, robot))
331338
self.sjoint.append(slider)
332-
333-
334339
robot.q = q
335340
self.step()
336341

roboticstoolbox/backends/PyPlot/RobotPlot.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
class RobotPlot():
1313

1414
def __init__(
15-
self, robot, ax, readonly, display=True,
16-
jointaxes=True, jointlabels=False, eeframe=True, shadow=True, name=True):
15+
self, robot, env, readonly, display=True,
16+
jointaxes=True, jointlabels=False, eeframe=True, shadow=True,
17+
name=True, options=None):
1718

1819
super(RobotPlot, self).__init__()
1920

@@ -25,7 +26,8 @@ def __init__(
2526
self.display = display
2627

2728
self.robot = robot
28-
self.ax = ax
29+
self.env = env
30+
self.ax = env.ax
2931

3032
# Line plot of robot links
3133
self.links = None
@@ -52,6 +54,23 @@ def __init__(
5254
self.shadow = shadow
5355
self.showname = name
5456

57+
defaults = {
58+
'robot': {'color': '#E16F6D', 'linewidth': 5},
59+
'shadow': {'color': 'lightgrey', 'linewidth': 3},
60+
'jointaxes': {'color': '#8FC1E2', 'linewidth': 2},
61+
'jointlabels': {},
62+
'jointaxislength': 0.2,
63+
'eex': {'color': '#F84752', 'linewidth': 2}, # '#EE9494'
64+
'eey': {'color': '#BADA55', 'linewidth': 2}, # '#93E7B0'
65+
'eez': {'color': '#54AEFF', 'linewidth': 2},
66+
'eelength': 0.06,
67+
}
68+
69+
if options is not None:
70+
for key, value in options.items():
71+
defaults[key] = {**defaults[key], **options[key]}
72+
self.options = defaults
73+
5574
def draw(self):
5675
if not self.display:
5776
return
@@ -96,13 +115,10 @@ def draw(self):
96115

97116
if self.eeframe:
98117
# Axes arrow transforms
99-
Tjx = SE3([0.06, 0, 0])
100-
Tjy = SE3([0, 0.06, 0])
101-
Tjz = SE3([0, 0, 0.06])
102-
103-
red = '#F84752' # '#EE9494'
104-
green = '#BADA55' # '#93E7B0'
105-
blue = '#54AEFF'
118+
len = self.options['eelength']
119+
Tjx = SE3([len, 0, 0])
120+
Tjy = SE3([0, len, 0])
121+
Tjz = SE3([0, 0, len])
106122

107123
# add new ee coordinate frame
108124
for link in self.robot.ee_links:
@@ -113,15 +129,15 @@ def draw(self):
113129
Tey = Te * Tjy
114130
Tez = Te * Tjz
115131

116-
xaxis = self._plot_quiver(Te.t, Tex.t, red, 2)
117-
yaxis = self._plot_quiver(Te.t, Tey.t, green, 2)
118-
zaxis = self._plot_quiver(Te.t, Tez.t, blue, 2)
132+
xaxis = self._plot_quiver(Te.t, Tex.t, self.options['eex'])
133+
yaxis = self._plot_quiver(Te.t, Tey.t, self.options['eey'])
134+
zaxis = self._plot_quiver(Te.t, Tez.t, self.options['eez'])
119135

120136
self.eeframes.extend([xaxis, yaxis, zaxis])
121137

122138
## Joint axes
123139

124-
# remove oldjoint z coordinates
140+
# remove old joint z axes
125141
if self.joints:
126142
for joint in self.joints:
127143
joint.remove()
@@ -151,18 +167,19 @@ def draw(self):
151167
direction = R[:, 0] # direction
152168

153169
if direction is not None:
154-
arrow = self._plot_quiver2(Tj.t, direction, 0.2, link.jindex, '#8FC1E2', 2)
170+
arrow = self._plot_quiver2(Tj.t, direction, link.jindex)
155171
self.joints.extend(arrow)
156172

157173

158174
def init(self):
159175

160176
self.drawn = True
161177

162-
limits = np.r_[-1, 1, -1, 1, -1, 1] * self.robot.reach * 1.5
163-
self.ax.set_xlim3d([limits[0], limits[1]])
164-
self.ax.set_ylim3d([limits[2], limits[3]])
165-
self.ax.set_zlim3d([limits[4], limits[5]])
178+
if self.env.limits is None:
179+
limits = np.r_[-1, 1, -1, 1, -1, 1] * self.robot.reach * 1.5
180+
self.ax.set_xlim3d([limits[0], limits[1]])
181+
self.ax.set_ylim3d([limits[2], limits[3]])
182+
self.ax.set_zlim3d([limits[4], limits[5]])
166183

167184
self.segments = self.robot.segments()
168185

@@ -179,45 +196,47 @@ def init(self):
179196
self.links = []
180197
self.sh_links = []
181198
for i in range(len(self.segments)):
182-
line, = self.ax.plot(
183-
0, 0, 0, linewidth=5, color='#E16F6D')
184-
self.links.append(line)
199+
185200

186201
# Plot the shadow of the robot links, draw first so robot is always
187202
# in front
188203
if self.shadow:
189204
shadow, = self.ax.plot(
190205
0, 0,
191-
linewidth=3, color='lightgrey')
206+
zorder=1,
207+
**self.options['shadow'])
192208
self.sh_links.append(shadow)
193209

210+
line, = self.ax.plot(
211+
0, 0, 0, **self.options['robot'])
212+
self.links.append(line)
213+
194214
self.eeframes = []
195215
self.joints = []
196216

197-
def _plot_quiver(self, p0, p1, col, width):
217+
def _plot_quiver(self, p0, p1, options):
198218
qv = self.ax.quiver(
199219
p0[0], p0[1], p0[2],
200220
p1[0] - p0[0],
201221
p1[1] - p0[1],
202222
p1[2] - p0[2],
203-
linewidth=width,
204-
color=col
223+
**options
205224
)
206225
return qv
207226

208-
def _plot_quiver2(self, p0, dir, len, j, col, width):
209-
vec = dir * len
227+
def _plot_quiver2(self, p0, dir, j):
228+
vec = dir * self.options['jointaxislength']
210229
start = p0 - vec / 2
211230
qv = self.ax.quiver(
212231
start[0], start[1], start[2],
213232
vec[0], vec[1], vec[2],
214-
linewidth=width,
215-
color=col
233+
zorder=5,
234+
**self.options['jointaxes']
216235
)
217236

218237
if self.jointlabels:
219-
pl = p0 + vec * 0.6
220-
label = self.ax.text(pl[0], pl[1], pl[2], f'q{j}')
238+
pl = p0 - vec * 0.6
239+
label = self.ax.text(pl[0], pl[1], pl[2], f'$q_{j}$', **self.options['jointlabels'] )
221240
return [qv, label]
222241
else:
223242
return [qv]

0 commit comments

Comments
 (0)