Spaces:
Running
Running
| <script lang="ts"> | |
| import type { Robot } from '../Robot.svelte.js'; | |
| interface Props { | |
| robot: Robot; | |
| } | |
| let { robot }: Props = $props(); | |
| const joints = $derived(robot.jointArray); | |
| const isManualControlEnabled = $derived(robot.isManualControlEnabled); | |
| function updateJoint(name: string, value: number) { | |
| if (!isManualControlEnabled) return; | |
| robot.updateJoint(name, value); | |
| } | |
| </script> | |
| <div class="bg-slate-800 border border-slate-600 rounded-lg p-4 space-y-4"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-lg font-semibold text-slate-100"> | |
| Robot Controls - {robot.id} | |
| </h3> | |
| <div class="flex items-center gap-2"> | |
| {#if isManualControlEnabled} | |
| <span class="text-green-400 text-sm">Manual Control</span> | |
| {:else} | |
| <span class="text-orange-400 text-sm">External Control</span> | |
| {/if} | |
| </div> | |
| </div> | |
| <div class="space-y-4"> | |
| {#each joints as joint} | |
| <div class="space-y-2"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-slate-200">{joint.name}</span> | |
| <span class="text-sm text-slate-400"> | |
| {joint.value.toFixed(1)}% | |
| </span> | |
| </div> | |
| <div class="flex items-center gap-4"> | |
| {#if joint.name.toLowerCase() === 'jaw' || joint.name.toLowerCase() === 'gripper'} | |
| <span class="text-xs text-slate-400 w-12">0% (closed)</span> | |
| <input | |
| type="range" | |
| min="0" | |
| max="100" | |
| step="1" | |
| value={joint.value} | |
| disabled={!isManualControlEnabled} | |
| oninput={(e) => updateJoint(joint.name, parseFloat(e.currentTarget.value))} | |
| class="flex-1 h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed" | |
| /> | |
| <span class="text-xs text-slate-400 w-12">100% (open)</span> | |
| {:else} | |
| <span class="text-xs text-slate-400 w-8">-100%</span> | |
| <input | |
| type="range" | |
| min="-100" | |
| max="100" | |
| step="1" | |
| value={joint.value} | |
| disabled={!isManualControlEnabled} | |
| oninput={(e) => updateJoint(joint.name, parseFloat(e.currentTarget.value))} | |
| class="flex-1 h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed" | |
| /> | |
| <span class="text-xs text-slate-400 w-8">+100%</span> | |
| {/if} | |
| </div> | |
| {#if joint.limits} | |
| <div class="text-xs text-slate-500"> | |
| URDF limits: {(joint.limits.lower)}° to {joint.limits.upper}° | |
| </div> | |
| {/if} | |
| </div> | |
| {/each} | |
| </div> | |
| </div> |