Skip to content

Commit 97abe5e

Browse files
committed
merge swift recording
2 parents bcce61f + 79235f1 commit 97abe5e

File tree

3 files changed

+163
-14
lines changed

3 files changed

+163
-14
lines changed

examples/swift_recording.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python
2+
"""
3+
@author Jesse Haviland
4+
"""
5+
6+
import roboticstoolbox as rtb
7+
import spatialmath as sm
8+
import numpy as np
9+
import qpsolvers as qp
10+
11+
"""
12+
This is an implementation of the controller from:
13+
J. Haviland and P. Corke, “A purely-reactive manipulability-maximising
14+
motion controller,” arXiv preprint arXiv:2002.11901,2020.
15+
"""
16+
17+
# Launch the simulator Swift
18+
env = rtb.backend.Swift()
19+
env.launch()
20+
21+
# Create a Panda robot object
22+
panda = rtb.models.Panda()
23+
24+
# Set joint angles to ready configuration
25+
panda.q = panda.qr
26+
27+
# Add the Panda to the simulator
28+
env.add(panda)
29+
30+
# The timestep for the simulation, 25ms
31+
dt = 0.025
32+
33+
# Start recording with a framerate of 1/dt and
34+
# call the video panda_swift_recording
35+
env.start_recording('panda_swift_recording', 1 / dt)
36+
37+
# Number of joint in the panda which we are controlling
38+
n = 7
39+
40+
# Set the desired end-effector pose
41+
Tep = panda.fkine() * sm.SE3(0.3, 0.2, 0.3)
42+
43+
arrived = False
44+
45+
while not arrived:
46+
47+
# The pose of the Panda's end-effector
48+
Te = panda.fkine()
49+
50+
# Transform from the end-effector to desired pose
51+
eTep = Te.inv() * Tep
52+
53+
# Spatial error
54+
e = np.sum(np.abs(np.r_[eTep.t, eTep.rpy() * np.pi/180]))
55+
56+
# Calulate the required end-effector spatial velocity for the robot
57+
# to approach the goal. Gain is set to 1.0
58+
v, arrived = rtb.p_servo(Te, Tep, 1.0)
59+
60+
# Gain term (lambda) for control minimisation
61+
Y = 0.01
62+
63+
# Quadratic component of objective function
64+
Q = np.eye(n + 6)
65+
66+
# Joint velocity component of Q
67+
Q[:n, :n] *= Y
68+
69+
# Slack component of Q
70+
Q[n:, n:] = (1 / e) * np.eye(6)
71+
72+
# The equality contraints
73+
Aeq = np.c_[panda.jacobe(), np.eye(6)]
74+
beq = v.reshape((6,))
75+
76+
# The inequality constraints for joint limit avoidance
77+
Ain = np.zeros((n + 6, n + 6))
78+
bin = np.zeros(n + 6)
79+
80+
# The minimum angle (in radians) in which the joint is allowed to approach
81+
# to its limit
82+
ps = 0.05
83+
84+
# The influence angle (in radians) in which the velocity damper
85+
# becomes active
86+
pi = 0.9
87+
88+
# Form the joint limit velocity damper
89+
Ain[:n, :n], bin[:n] = panda.joint_velocity_damper(ps, pi, n)
90+
91+
# Linear component of objective function: the manipulability Jacobian
92+
c = np.r_[-panda.jacobm().reshape((n,)), np.zeros(6)]
93+
94+
# The lower and upper bounds on the joint velocity and slack variable
95+
lb = -np.r_[panda.qdlim[:n], 10 * np.ones(6)]
96+
ub = np.r_[panda.qdlim[:n], 10 * np.ones(6)]
97+
98+
# Solve for the joint velocities dq
99+
qd = qp.solve_qp(Q, c, Ain, bin, Aeq, beq, lb=lb, ub=ub)
100+
101+
# Apply the joint velocities to the Panda
102+
panda.qd[:n] = qd[:n]
103+
104+
# Step the simulator by 50 ms
105+
env.step(dt)
106+
107+
# Stop recording and save the video (to the downloads folder)
108+
env.stop_recording()

roboticstoolbox/backend/Swift/Swift.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ def __init__(self, realtime=True, display=True):
7474
self.realtime = realtime
7575
self.display = display
7676

77+
self.recording = False
78+
7779
if self.display and sw is None:
7880
_import_swift()
7981

@@ -96,11 +98,11 @@ def launch(self):
9698
sw.start_servers(self.outq, self.inq)
9799
self.last_time = time.time()
98100

99-
def step(self, dt=50):
101+
def step(self, dt=0.05):
100102
"""
101103
Update the graphical scene
102104
103-
:param dt: time step in milliseconds, defaults to 50
105+
:param dt: time step in seconds, defaults to 0.05
104106
:type dt: int, optional
105107
106108
``env.step(args)`` triggers an update of the 3D scene in the Swift
@@ -133,11 +135,11 @@ def step(self, dt=50):
133135

134136
# If realtime is set, delay progress if we are running too quickly
135137
if self.realtime:
136-
time_taken = (time.time() - self.last_time) * 1000
138+
time_taken = (time.time() - self.last_time)
137139
diff = dt - time_taken
138140

139141
if diff > 0:
140-
time.sleep(diff / 1000)
142+
time.sleep(diff)
141143

142144
self.last_time = time.time()
143145

@@ -251,6 +253,46 @@ def remove(self):
251253

252254
super().remove()
253255

256+
def start_recording(self, file_name, framerate):
257+
"""
258+
Start recording the canvas in the Swift simulator
259+
260+
:param file_name: The file name for which the video will be saved as
261+
:type file_name: string
262+
:param framerate: The framerate of the video - to be timed correctly,
263+
this should equalt 1 / dt where dt is the time supplied to the
264+
step function
265+
:type framerate: float
266+
267+
``env.start_recording(file_name)`` starts recording the simulation
268+
scene and will save it as file_name once
269+
``env.start_recording(file_name)`` is called
270+
"""
271+
272+
if not self.recording:
273+
self._send_socket('start_recording', [framerate, file_name])
274+
self.recording = True
275+
else:
276+
raise ValueError(
277+
"You are already recording, you can only record one video"
278+
" at a time")
279+
280+
def stop_recording(self):
281+
"""
282+
Start recording the canvas in the Swift simulator. This is optional
283+
as the video will be automatically saved when the python script exits
284+
285+
``env.stop_recording()`` stops the recording of the simulation, can
286+
only be called after ``env.start_recording(file_name)``
287+
"""
288+
289+
if self.recording:
290+
self._send_socket('stop_recording')
291+
else:
292+
raise ValueError(
293+
"You must call swift.start_recording(file_name) before trying"
294+
" to stop the recording")
295+
254296
def _step_robots(self, dt):
255297

256298
for robot in self.robots:
@@ -261,7 +303,7 @@ def _step_robots(self, dt):
261303
if robot.control_type == 'v':
262304

263305
for i in range(robot.n):
264-
robot.q[i] += robot.qd[i] * (dt / 1000)
306+
robot.q[i] += robot.qd[i] * (dt)
265307

266308
if np.any(robot.qlim[:, i] != 0) and \
267309
not np.any(np.isnan(robot.qlim[:, i])):
@@ -285,8 +327,8 @@ def _step_shapes(self, dt):
285327
t = T.t
286328
r = T.rpy('rad')
287329

288-
t += shape.v[:3] * (dt / 1000)
289-
r += shape.v[3:] * (dt / 1000)
330+
t += shape.v[:3] * (dt)
331+
r += shape.v[3:] * (dt)
290332

291333
shape.base = sm.SE3(t) * sm.SE3.RPY(r)
292334

@@ -298,7 +340,7 @@ def _draw_all(self):
298340
for i in range(len(self.shapes)):
299341
self._send_socket('shape_poses', [i, self.shapes[i].fk_dict()])
300342

301-
def _send_socket(self, code, data):
343+
def _send_socket(self, code, data=None):
302344
msg = [code, data]
303345

304346
self.outq.put(msg)

setup.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
with open(path.join(here, 'RELEASE'), encoding='utf-8') as f:
4444
release = f.read()
4545

46+
4647
def package_files(directory):
4748
paths = []
4849
for (pathhere, _, filenames) in os.walk(directory):
@@ -94,24 +95,22 @@ def package_files(directory):
9495
'Programming Language :: Python :: 3.7',
9596
'Programming Language :: Python :: 3.8',
9697
'Programming Language :: Python :: 3.9',
97-
],
98+
],
9899

99100
python_requires='>=3.6',
100-
101+
101102
project_urls={
102103
'Documentation': 'https://petercorke.github.io/roboticstoolbox-python',
103104
'Source': 'https://github.com/petercorke/roboticstoolbox-python',
104105
'Tracker': 'https://github.com/petercorke/roboticstoolbox-python/issues',
105106
'Coverage': 'https://codecov.io/gh/petercorke/roboticstoolbox-python'
106107
},
107108

108-
url='https://github.com/petercorke/roboticstoolbox-python',
109-
110109
ext_modules=[frne],
111110

112111
keywords='python robotics robotics-toolbox kinematics dynamics' \
113-
' motion-planning trajectory-generation jacobian hessian control' \
114-
' simulation robot-manipulator mobile-robot'
112+
' motion-planning trajectory-generation jacobian hessian' \
113+
' control simulation robot-manipulator mobile-robot',
115114

116115
packages=find_packages(exclude=["tests", "examples", "notebooks"]),
117116

0 commit comments

Comments
 (0)