8bitkick
commited on
Commit
·
e6b41f4
1
Parent(s):
7b6b2a4
Layout improvements
Browse files
reachy_mini_app_example/robot_viz.html
CHANGED
|
@@ -15,23 +15,32 @@
|
|
| 15 |
height: 100vh;
|
| 16 |
}
|
| 17 |
#status {
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
left: 10px;
|
| 21 |
-
background: rgba(255, 255, 255, 0.9);
|
| 22 |
-
padding: 10px 15px;
|
| 23 |
border-radius: 5px;
|
| 24 |
font-size: 16px;
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
| 27 |
-
.ok { color: #
|
| 28 |
-
.err { color: #
|
| 29 |
#data-panel {
|
| 30 |
position: absolute;
|
| 31 |
-
|
| 32 |
left: 10px;
|
| 33 |
display: flex;
|
| 34 |
-
flex-direction:
|
| 35 |
gap: 10px;
|
| 36 |
z-index: 100;
|
| 37 |
}
|
|
@@ -41,7 +50,7 @@
|
|
| 41 |
border-radius: 5px;
|
| 42 |
font-size: 16px;
|
| 43 |
width: 270px;
|
| 44 |
-
height:
|
| 45 |
display: flex;
|
| 46 |
flex-direction: column;
|
| 47 |
font-family: 'VT323', monospace;
|
|
@@ -58,6 +67,7 @@
|
|
| 58 |
margin: 3px 0;
|
| 59 |
display: flex;
|
| 60 |
justify-content: space-between;
|
|
|
|
| 61 |
gap: 15px;
|
| 62 |
}
|
| 63 |
.joint-name {
|
|
@@ -65,6 +75,15 @@
|
|
| 65 |
flex: 0 0 140px;
|
| 66 |
text-align: left;
|
| 67 |
white-space: nowrap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
.joint-value {
|
| 70 |
font-weight: bold;
|
|
@@ -76,8 +95,8 @@
|
|
| 76 |
background: rgba(0, 0, 0, 0.7);
|
| 77 |
padding: 15px;
|
| 78 |
border-radius: 5px;
|
| 79 |
-
|
| 80 |
-
height:
|
| 81 |
box-sizing: border-box;
|
| 82 |
}
|
| 83 |
#chart {
|
|
@@ -87,8 +106,8 @@
|
|
| 87 |
</style>
|
| 88 |
</head>
|
| 89 |
<body>
|
| 90 |
-
<div id="status">Loading...</div>
|
| 91 |
<div id="data-panel">
|
|
|
|
| 92 |
<div id="joints">
|
| 93 |
<div id="joints-list">Waiting for data...</div>
|
| 94 |
</div>
|
|
@@ -139,13 +158,13 @@
|
|
| 139 |
bgCanvas.height = 1024;
|
| 140 |
const bgCtx = bgCanvas.getContext('2d');
|
| 141 |
const bgGradient = bgCtx.createLinearGradient(0, 0, 0, bgCanvas.height);
|
| 142 |
-
bgGradient.addColorStop(0.0, '#
|
| 143 |
-
bgGradient.addColorStop(0.
|
| 144 |
-
bgGradient.addColorStop(0.
|
| 145 |
-
bgGradient.addColorStop(0.
|
| 146 |
-
bgGradient.addColorStop(0.
|
| 147 |
-
bgGradient.addColorStop(0.
|
| 148 |
-
bgGradient.addColorStop(1.0, '#
|
| 149 |
bgCtx.fillStyle = bgGradient;
|
| 150 |
bgCtx.fillRect(0, 0, bgCanvas.width, bgCanvas.height);
|
| 151 |
const bgTexture = new THREE.CanvasTexture(bgCanvas);
|
|
@@ -231,15 +250,7 @@
|
|
| 231 |
animation: false,
|
| 232 |
plugins: {
|
| 233 |
legend: {
|
| 234 |
-
display:
|
| 235 |
-
position: 'right',
|
| 236 |
-
align: 'start',
|
| 237 |
-
labels: {
|
| 238 |
-
color: '#ffffff',
|
| 239 |
-
font: { size: 10 },
|
| 240 |
-
boxWidth: 20,
|
| 241 |
-
padding: 8
|
| 242 |
-
}
|
| 243 |
}
|
| 244 |
},
|
| 245 |
scales: {
|
|
@@ -363,11 +374,11 @@
|
|
| 363 |
function connectWebSocket() {
|
| 364 |
robotClient.onStateChange((event, data) => {
|
| 365 |
if (event === 'connected') {
|
| 366 |
-
statusEl.innerHTML = '<span class="ok"
|
| 367 |
} else if (event === 'disconnected') {
|
| 368 |
-
statusEl.innerHTML = '<span class="err"
|
| 369 |
} else if (event === 'error') {
|
| 370 |
-
statusEl.innerHTML = '<span class="err"
|
| 371 |
} else if (event === 'data') {
|
| 372 |
updateRobotJoints(data);
|
| 373 |
updateJointsDisplay(data);
|
|
@@ -425,15 +436,24 @@
|
|
| 425 |
const roll = data.head_pose.roll * 180 / Math.PI;
|
| 426 |
|
| 427 |
html += `<div class="joint-item">
|
| 428 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 429 |
<span class="joint-value">${yaw.toFixed(2)}°</span>
|
| 430 |
</div>`;
|
| 431 |
html += `<div class="joint-item">
|
| 432 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 433 |
<span class="joint-value">${pitch.toFixed(2)}°</span>
|
| 434 |
</div>`;
|
| 435 |
html += `<div class="joint-item">
|
| 436 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 437 |
<span class="joint-value">${roll.toFixed(2)}°</span>
|
| 438 |
</div>`;
|
| 439 |
|
|
@@ -448,11 +468,17 @@
|
|
| 448 |
const rightAntenna = data.antennas_position[1] * 180 / Math.PI;
|
| 449 |
|
| 450 |
html += `<div class="joint-item">
|
| 451 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 452 |
<span class="joint-value">${leftAntenna.toFixed(2)}°</span>
|
| 453 |
</div>`;
|
| 454 |
html += `<div class="joint-item">
|
| 455 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 456 |
<span class="joint-value">${rightAntenna.toFixed(2)}°</span>
|
| 457 |
</div>`;
|
| 458 |
|
|
@@ -464,7 +490,10 @@
|
|
| 464 |
if (data.body_yaw !== undefined) {
|
| 465 |
const bodyYaw = data.body_yaw * 180 / Math.PI;
|
| 466 |
html += `<div class="joint-item">
|
| 467 |
-
<span class="joint-name">
|
|
|
|
|
|
|
|
|
|
| 468 |
<span class="joint-value">${bodyYaw.toFixed(2)}°</span>
|
| 469 |
</div>`;
|
| 470 |
|
|
|
|
| 15 |
height: 100vh;
|
| 16 |
}
|
| 17 |
#status {
|
| 18 |
+
background: rgba(0, 0, 0, 0.7);
|
| 19 |
+
padding: 15px;
|
|
|
|
|
|
|
|
|
|
| 20 |
border-radius: 5px;
|
| 21 |
font-size: 16px;
|
| 22 |
+
color: white;
|
| 23 |
+
width: 270px;
|
| 24 |
+
box-sizing: border-box;
|
| 25 |
+
display: flex;
|
| 26 |
+
align-items: center;
|
| 27 |
+
gap: 8px;
|
| 28 |
+
font-family: 'VT323', monospace;
|
| 29 |
+
}
|
| 30 |
+
.connection-led {
|
| 31 |
+
width: 8px;
|
| 32 |
+
height: 8px;
|
| 33 |
+
border-radius: 50%;
|
| 34 |
+
display: inline-block;
|
| 35 |
}
|
| 36 |
+
.ok .connection-led { background-color: #00ff00; box-shadow: 0 0 8px #00ff00; }
|
| 37 |
+
.err .connection-led { background-color: #ff0000; box-shadow: 0 0 8px #ff0000; }
|
| 38 |
#data-panel {
|
| 39 |
position: absolute;
|
| 40 |
+
top: 10px;
|
| 41 |
left: 10px;
|
| 42 |
display: flex;
|
| 43 |
+
flex-direction: column;
|
| 44 |
gap: 10px;
|
| 45 |
z-index: 100;
|
| 46 |
}
|
|
|
|
| 50 |
border-radius: 5px;
|
| 51 |
font-size: 16px;
|
| 52 |
width: 270px;
|
| 53 |
+
height: 200px;
|
| 54 |
display: flex;
|
| 55 |
flex-direction: column;
|
| 56 |
font-family: 'VT323', monospace;
|
|
|
|
| 67 |
margin: 3px 0;
|
| 68 |
display: flex;
|
| 69 |
justify-content: space-between;
|
| 70 |
+
align-items: center;
|
| 71 |
gap: 15px;
|
| 72 |
}
|
| 73 |
.joint-name {
|
|
|
|
| 75 |
flex: 0 0 140px;
|
| 76 |
text-align: left;
|
| 77 |
white-space: nowrap;
|
| 78 |
+
display: flex;
|
| 79 |
+
align-items: center;
|
| 80 |
+
gap: 8px;
|
| 81 |
+
}
|
| 82 |
+
.joint-color-dot {
|
| 83 |
+
width: 8px;
|
| 84 |
+
height: 8px;
|
| 85 |
+
border-radius: 50%;
|
| 86 |
+
display: inline-block;
|
| 87 |
}
|
| 88 |
.joint-value {
|
| 89 |
font-weight: bold;
|
|
|
|
| 95 |
background: rgba(0, 0, 0, 0.7);
|
| 96 |
padding: 15px;
|
| 97 |
border-radius: 5px;
|
| 98 |
+
width: 270px;
|
| 99 |
+
height: 200px;
|
| 100 |
box-sizing: border-box;
|
| 101 |
}
|
| 102 |
#chart {
|
|
|
|
| 106 |
</style>
|
| 107 |
</head>
|
| 108 |
<body>
|
|
|
|
| 109 |
<div id="data-panel">
|
| 110 |
+
<div id="status">Loading...</div>
|
| 111 |
<div id="joints">
|
| 112 |
<div id="joints-list">Waiting for data...</div>
|
| 113 |
</div>
|
|
|
|
| 158 |
bgCanvas.height = 1024;
|
| 159 |
const bgCtx = bgCanvas.getContext('2d');
|
| 160 |
const bgGradient = bgCtx.createLinearGradient(0, 0, 0, bgCanvas.height);
|
| 161 |
+
bgGradient.addColorStop(0.0, '#f7a072'); // warm orange
|
| 162 |
+
bgGradient.addColorStop(0.08, '#e97a5b'); // orange-red
|
| 163 |
+
bgGradient.addColorStop(0.18, '#cf4958'); // rose-orange
|
| 164 |
+
bgGradient.addColorStop(0.32, '#8e2a6a'); // purple-rose
|
| 165 |
+
bgGradient.addColorStop(0.55, '#4b136f'); // rich purple-magenta
|
| 166 |
+
bgGradient.addColorStop(0.78, '#1a0b4b'); // deep purple
|
| 167 |
+
bgGradient.addColorStop(1.0, '#0b032d'); // very deep purple
|
| 168 |
bgCtx.fillStyle = bgGradient;
|
| 169 |
bgCtx.fillRect(0, 0, bgCanvas.width, bgCanvas.height);
|
| 170 |
const bgTexture = new THREE.CanvasTexture(bgCanvas);
|
|
|
|
| 250 |
animation: false,
|
| 251 |
plugins: {
|
| 252 |
legend: {
|
| 253 |
+
display: false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
}
|
| 255 |
},
|
| 256 |
scales: {
|
|
|
|
| 374 |
function connectWebSocket() {
|
| 375 |
robotClient.onStateChange((event, data) => {
|
| 376 |
if (event === 'connected') {
|
| 377 |
+
statusEl.innerHTML = '<span class="ok"><span class="connection-led"></span> Reachy Mini</span>';
|
| 378 |
} else if (event === 'disconnected') {
|
| 379 |
+
statusEl.innerHTML = '<span class="err"><span class="connection-led"></span>Disconnected. Reconnecting...</span>';
|
| 380 |
} else if (event === 'error') {
|
| 381 |
+
statusEl.innerHTML = '<span class="err"><span class="connection-led"></span>WebSocket error</span>';
|
| 382 |
} else if (event === 'data') {
|
| 383 |
updateRobotJoints(data);
|
| 384 |
updateJointsDisplay(data);
|
|
|
|
| 436 |
const roll = data.head_pose.roll * 180 / Math.PI;
|
| 437 |
|
| 438 |
html += `<div class="joint-item">
|
| 439 |
+
<span class="joint-name">
|
| 440 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['head yaw'] || '#ffffff'}"></span>
|
| 441 |
+
head yaw
|
| 442 |
+
</span>
|
| 443 |
<span class="joint-value">${yaw.toFixed(2)}°</span>
|
| 444 |
</div>`;
|
| 445 |
html += `<div class="joint-item">
|
| 446 |
+
<span class="joint-name">
|
| 447 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['head pitch'] || '#ffffff'}"></span>
|
| 448 |
+
head pitch
|
| 449 |
+
</span>
|
| 450 |
<span class="joint-value">${pitch.toFixed(2)}°</span>
|
| 451 |
</div>`;
|
| 452 |
html += `<div class="joint-item">
|
| 453 |
+
<span class="joint-name">
|
| 454 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['head roll'] || '#ffffff'}"></span>
|
| 455 |
+
head roll
|
| 456 |
+
</span>
|
| 457 |
<span class="joint-value">${roll.toFixed(2)}°</span>
|
| 458 |
</div>`;
|
| 459 |
|
|
|
|
| 468 |
const rightAntenna = data.antennas_position[1] * 180 / Math.PI;
|
| 469 |
|
| 470 |
html += `<div class="joint-item">
|
| 471 |
+
<span class="joint-name">
|
| 472 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['left antenna'] || '#ffffff'}"></span>
|
| 473 |
+
left antenna
|
| 474 |
+
</span>
|
| 475 |
<span class="joint-value">${leftAntenna.toFixed(2)}°</span>
|
| 476 |
</div>`;
|
| 477 |
html += `<div class="joint-item">
|
| 478 |
+
<span class="joint-name">
|
| 479 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['right antenna'] || '#ffffff'}"></span>
|
| 480 |
+
right antenna
|
| 481 |
+
</span>
|
| 482 |
<span class="joint-value">${rightAntenna.toFixed(2)}°</span>
|
| 483 |
</div>`;
|
| 484 |
|
|
|
|
| 490 |
if (data.body_yaw !== undefined) {
|
| 491 |
const bodyYaw = data.body_yaw * 180 / Math.PI;
|
| 492 |
html += `<div class="joint-item">
|
| 493 |
+
<span class="joint-name">
|
| 494 |
+
<span class="joint-color-dot" style="background-color: ${jointColors['body yaw'] || '#ffffff'}"></span>
|
| 495 |
+
body yaw
|
| 496 |
+
</span>
|
| 497 |
<span class="joint-value">${bodyYaw.toFixed(2)}°</span>
|
| 498 |
</div>`;
|
| 499 |
|