Skip to content

Commit 112ee04

Browse files
authored
Merge pull request #10 from johnwason/pr/ViewerJavascriptControl
Add ability to control tesseract_viewer_python from javascript
2 parents f2a6247 + c88120d commit 112ee04

File tree

6 files changed

+233
-4
lines changed

6 files changed

+233
-4
lines changed

tesseract_viewer_python/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,7 @@ venv.bak/
126126
dmypy.json
127127

128128
# Pyre type checker
129-
.pyre/
129+
.pyre/
130+
131+
node_modules
132+
package-lock.json
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<html>
2+
<head>
3+
<script
4+
src="https://code.jquery.com/jquery-3.5.1.js"
5+
crossorigin="anonymous"></script>
6+
</head>
7+
<body>
8+
<iframe src="http://localhost:8000/index.html?noupdate=true" width="100%" height="100%" id="viewer"></iframe>
9+
10+
<script>
11+
12+
function sleep(ms) {
13+
return new Promise(resolve => setTimeout(resolve, ms));
14+
}
15+
16+
async function example_loop()
17+
{
18+
while(true)
19+
{
20+
viewer = document.getElementById("viewer")
21+
viewer.contentWindow.postMessage(
22+
{
23+
"command": "joint_positions",
24+
"joint_names": ["joint_1", "joint_2", "joint_3","joint_4","joint_5","joint_6"],
25+
"joint_positions": [0.6, 0.2, 0.3, 0.4, 0.5, 0.6]
26+
},
27+
"*")
28+
await sleep(1000);
29+
viewer.contentWindow.postMessage(
30+
{
31+
"command": "joint_positions",
32+
"joint_names": ["joint_1", "joint_2", "joint_3","joint_4","joint_5","joint_6"],
33+
"joint_positions": [-0.6, -0.2, -0.3, -0.4, -0.5, -0.6]
34+
},
35+
"*");
36+
await sleep(1000);
37+
38+
}
39+
}
40+
41+
$("#viewer").ready(function(){
42+
console.log("Viewer loaded")
43+
}
44+
).delay(5000).queue(function()
45+
{
46+
example_loop();
47+
})
48+
49+
</script>
50+
</body>
51+
52+
</html>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<html>
2+
<head>
3+
<script
4+
src="https://code.jquery.com/jquery-3.5.1.js" crossorigin="anonymous"></script>
5+
</head>
6+
<body>
7+
<iframe src="http://localhost:8000/index.html?noupdate=true" width="100%" height="100%" id="viewer"></iframe>
8+
9+
<script>
10+
11+
12+
function example_set_trajectory()
13+
{
14+
15+
viewer = document.getElementById("viewer")
16+
trajectory = [
17+
[0.6, 0.2, 0.3, 0.4, 0.5, 0.6, 0], // Joint positions, with time as last element
18+
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 5],
19+
[-0.7, 0.4, -0.9, -0.1, 0.1, 0.2, 10],
20+
]; // Array of waypoints for trajectory
21+
viewer.contentWindow.postMessage(
22+
{
23+
"command": "joint_trajectory",
24+
"joint_names": ["joint_1", "joint_2", "joint_3","joint_4","joint_5","joint_6"],
25+
"joint_trajectory": trajectory
26+
},
27+
"*")
28+
}
29+
30+
$("#viewer").ready(function(){
31+
console.log("Viewer loaded")
32+
}
33+
).delay(5000).queue(function()
34+
{
35+
example_set_trajectory();
36+
})
37+
38+
</script>
39+
</body>
40+
41+
</html>

tesseract_viewer_python/tesseract_viewer/resources/static/tesseract_viewer.js

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class TesseractViewer {
2727
constructor(canvasElement) {
2828
this._scene_etag = null;
2929
this._trajectory_etag = null;
30+
this._disable_update_trajectory = false;
3031
// Create canvas and engine.
3132
this._canvas = document.getElementById(canvasElement);
3233
this._engine = new BABYLON.Engine(this._canvas, true);
@@ -67,7 +68,17 @@ class TesseractViewer {
6768
});
6869
yield this.enableVR();
6970
let _this = this;
70-
setTimeout(() => _this.updateTrajectory(), 2000);
71+
const queryString = window.location.search;
72+
const urlParams = new URLSearchParams(queryString);
73+
let do_update = true;
74+
if (urlParams.has("noupdate")) {
75+
if (urlParams.get("noupdate") === "true") {
76+
do_update = false;
77+
}
78+
}
79+
if (do_update) {
80+
setTimeout(() => _this.updateTrajectory(), 2000);
81+
}
7182
//this._scene.debugLayer.show();
7283
});
7384
}
@@ -157,6 +168,9 @@ class TesseractViewer {
157168
}
158169
updateTrajectory() {
159170
return __awaiter(this, void 0, void 0, function* () {
171+
if (this._disable_update_trajectory) {
172+
return;
173+
}
160174
let fetch_res;
161175
let _this = this;
162176
try {
@@ -199,6 +213,36 @@ class TesseractViewer {
199213
}
200214
});
201215
}
216+
disableUpdateTrajectory() {
217+
this._disable_update_trajectory = true;
218+
}
219+
enableUpdateTrajectory() {
220+
this._disable_update_trajectory = false;
221+
}
222+
setJointPositions(joint_names, joint_positions) {
223+
let trajectory = [[...joint_positions, 0], [...joint_positions, 100000]];
224+
this.setTrajectory(joint_names, trajectory);
225+
}
226+
/*
227+
trajectory format:
228+
[
229+
[0.1,0.2,0.3,0.4,0.5,0.6, 0] // waypoint 1, last element is time
230+
[0.11,0.21,0.31,0.41,0.51,0.61, 1] // waypoint 2, last element is time
231+
... // more waypoints
232+
]
233+
Position is in radians or meters, time is in seconds
234+
*/
235+
setTrajectory(joint_names, trajectory) {
236+
try {
237+
if (this._joint_trajectory !== null) {
238+
this._joint_trajectory.stop();
239+
this._joint_trajectory = null;
240+
}
241+
}
242+
catch (_a) { }
243+
this._joint_trajectory = new JointTrajectoryAnimation(this._scene, joint_names, trajectory, true, 0);
244+
this._joint_trajectory.start();
245+
}
202246
}
203247
class JointTrajectoryAnimation {
204248
constructor(scene, joint_names, trajectory, use_time, loop_time) {
@@ -343,8 +387,20 @@ window.addEventListener('DOMContentLoaded', function () {
343387
return __awaiter(this, void 0, void 0, function* () {
344388
// Create the game using the 'renderCanvas'.
345389
let viewer = new TesseractViewer('renderCanvas');
390+
window.tesseract_viewer = viewer;
346391
// Create the scene.
347392
yield viewer.createScene();
393+
window.addEventListener("message", function (event) {
394+
let data = event.data;
395+
if (data.command === "joint_positions") {
396+
viewer.disableUpdateTrajectory();
397+
viewer.setJointPositions(data.joint_names, data.joint_positions);
398+
}
399+
if (data.command === "joint_trajectory") {
400+
viewer.disableUpdateTrajectory();
401+
viewer.setTrajectory(data.joint_names, data.joint_trajectory);
402+
}
403+
});
348404
// Start render loop.
349405
viewer.doRender();
350406
});

tesseract_viewer_python/tesseract_viewer/resources/static/tesseract_viewer.ts

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class TesseractViewer {
3434
private _joint_trajectory: JointTrajectoryAnimation;
3535
private _scene_etag = null;
3636
private _trajectory_etag= null;
37+
private _disable_update_trajectory = false;
3738

3839
constructor(canvasElement : string) {
3940
// Create canvas and engine.
@@ -89,7 +90,22 @@ class TesseractViewer {
8990

9091
await this.enableVR();
9192
let _this = this;
92-
setTimeout(() => _this.updateTrajectory(),2000);
93+
94+
const queryString = window.location.search;
95+
const urlParams = new URLSearchParams(queryString);
96+
let do_update = true;
97+
if (urlParams.has("noupdate"))
98+
{
99+
if (urlParams.get("noupdate") === "true")
100+
{
101+
do_update = false;
102+
}
103+
}
104+
105+
if (do_update)
106+
{
107+
setTimeout(() => _this.updateTrajectory(),2000);
108+
}
93109

94110
//this._scene.debugLayer.show();
95111

@@ -195,6 +211,10 @@ class TesseractViewer {
195211

196212
async updateTrajectory(): Promise<void>
197213
{
214+
if (this._disable_update_trajectory)
215+
{
216+
return;
217+
}
198218
let fetch_res: Response;
199219
let _this = this;
200220
try
@@ -250,6 +270,46 @@ class TesseractViewer {
250270
}
251271
}
252272

273+
public disableUpdateTrajectory() : void
274+
{
275+
this._disable_update_trajectory = true;
276+
}
277+
278+
public enableUpdateTrajectory() : void
279+
{
280+
this._disable_update_trajectory = false;
281+
}
282+
283+
public setJointPositions(joint_names : string[], joint_positions: number[])
284+
{
285+
let trajectory = [[...joint_positions,0],[...joint_positions,100000]];
286+
this.setTrajectory(joint_names, trajectory);
287+
}
288+
289+
/*
290+
trajectory format:
291+
[
292+
[0.1,0.2,0.3,0.4,0.5,0.6, 0] // waypoint 1, last element is time
293+
[0.11,0.21,0.31,0.41,0.51,0.61, 1] // waypoint 2, last element is time
294+
... // more waypoints
295+
]
296+
Position is in radians or meters, time is in seconds
297+
*/
298+
public setTrajectory(joint_names: string[], trajectory: number[][])
299+
{
300+
try
301+
{
302+
if (this._joint_trajectory !== null)
303+
{
304+
this._joint_trajectory.stop();
305+
this._joint_trajectory = null;
306+
}
307+
}
308+
catch {}
309+
this._joint_trajectory = new JointTrajectoryAnimation(this._scene, joint_names, trajectory, true, 0);
310+
this._joint_trajectory.start();
311+
}
312+
253313
}
254314

255315
class JointTrajectoryAnimation
@@ -466,9 +526,26 @@ class JointTrajectoryAnimation
466526
window.addEventListener('DOMContentLoaded', async function() {
467527
// Create the game using the 'renderCanvas'.
468528
let viewer = new TesseractViewer('renderCanvas');
529+
530+
(window as any).tesseract_viewer = viewer;
469531

470532
// Create the scene.
471533
await viewer.createScene();
534+
535+
window.addEventListener("message", function(event: Event)
536+
{
537+
let data = (event as MessageEvent).data;
538+
if (data.command === "joint_positions")
539+
{
540+
viewer.disableUpdateTrajectory();
541+
viewer.setJointPositions(data.joint_names, data.joint_positions)
542+
}
543+
if (data.command === "joint_trajectory")
544+
{
545+
viewer.disableUpdateTrajectory();
546+
viewer.setTrajectory(data.joint_names, data.joint_trajectory)
547+
}
548+
});
472549

473550
// Start render loop.
474551
viewer.doRender();

tesseract_viewer_python/tesseract_viewer/tesseract_viewer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def __init__(self, request, client_address, server ):
5353
super(_TesseractViewerRequestHandler,self).__init__(request,client_address,server)
5454

5555
def do_file(self, send_data):
56-
path = self.path
56+
path = self.path.split("?")[0]
5757
if (self.path == "/"):
5858
path = "/index.html"
5959
path=path[1:]

0 commit comments

Comments
 (0)