- Controle: opt-in de movimento fisico, botao "segure para mover" (mouse, toque e teclado), sliders das articulacoes tambem so movem enquanto pressionados; velocidade e interpolacao ficam no servidor - sequencias prontas e posturas salvas: previa so na tela ou execucao segurando o botao ate o fim; soltar interrompe na hora - posturas com nome inline (sem prompt), exclusao confirmada inline, exportar/importar; posturas aparecem na paleta (Ctrl+K) - Calibracao: testes de fim de curso por canal, marcar limites e tabela editavel com validacao antes de salvar - Diagnostico (antigo Servos): ao vivo limitado a 10/s, bloqueado quando o braco esta com os motores - desenho esquematico do braco em SVG com previa animada - servidor: evento 'motores' tambem ao ligar canais; renovar no alvo devolve movendo=false para a sequencia avancar - aba escondida ou E-Stop soltam o braco e desativam o movimento Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
2.5 KiB
Svelte
89 lines
2.5 KiB
Svelte
<script lang="ts">
|
|
import { Power } from '@lucide/svelte';
|
|
import { onDestroy, onMount } from 'svelte';
|
|
import { braco } from '../lib/braco.svelte';
|
|
import Abas from '../lib/componentes/Abas.svelte';
|
|
import Selo from '../lib/componentes/Selo.svelte';
|
|
import { estado } from '../lib/estado.svelte';
|
|
import { registrarNaPaleta } from '../lib/paleta.svelte';
|
|
import Calibracao from './movimento/Calibracao.svelte';
|
|
import Controle from './movimento/Controle.svelte';
|
|
import Diagnostico from './movimento/Diagnostico.svelte';
|
|
|
|
type Aba = 'controle' | 'calibracao' | 'diagnostico';
|
|
let aba = $state<Aba>('controle');
|
|
const motores = $derived(estado.motores);
|
|
|
|
onMount(() => {
|
|
braco.carregar();
|
|
});
|
|
// Posturas na paleta: carregar como alvo (mover exige segurar o botão).
|
|
const sair = registrarNaPaleta(() =>
|
|
(braco.status?.posturas ?? []).map((p, i) => ({
|
|
id: 'postura-' + i,
|
|
grupo: 'Posturas do braço',
|
|
titulo: 'Carregar ' + p.nome,
|
|
fazer: () => (braco.alvo = [...p.angulos]),
|
|
})),
|
|
);
|
|
onDestroy(() => {
|
|
sair();
|
|
braco.soltar();
|
|
});
|
|
</script>
|
|
|
|
<div class="movimento">
|
|
<div class="estado">
|
|
<div class="linha">
|
|
{#if !motores?.disponivel}
|
|
<Selo tom="aviso">PCA9685 indisponível neste servidor</Selo>
|
|
{:else if estado.estop.ativo || motores.travado}
|
|
<Selo tom="perigo">Travado pelo E-Stop</Selo>
|
|
{:else if motores.ativos.length}
|
|
<Selo tom="ok">Motores ligados · {motores.dono === 'braco' ? 'braço' : 'diagnóstico'} · canais {motores.ativos.join(', ')}</Selo>
|
|
{:else}
|
|
<Selo>Motores desligados</Selo>
|
|
{/if}
|
|
{#if motores?.erro}<span class="erro pequeno-texto">{motores.erro}</span>{/if}
|
|
</div>
|
|
<button class="btn" onclick={() => braco.pararMotores()} disabled={!motores?.ativos.length}>
|
|
<Power size={16} /> Desligar motores
|
|
</button>
|
|
</div>
|
|
|
|
<Abas
|
|
rotulo="Movimento"
|
|
bind:ativa={aba}
|
|
abas={[
|
|
{ id: 'controle', titulo: 'Controle' },
|
|
{ id: 'calibracao', titulo: 'Calibração' },
|
|
{ id: 'diagnostico', titulo: 'Diagnóstico' },
|
|
]}
|
|
/>
|
|
|
|
{#if aba === 'controle'}
|
|
<Controle />
|
|
{:else if aba === 'calibracao'}
|
|
<Calibracao />
|
|
{:else}
|
|
<Diagnostico />
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
.movimento {
|
|
display: grid;
|
|
gap: var(--e-4);
|
|
}
|
|
.estado {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: var(--e-3);
|
|
flex-wrap: wrap;
|
|
}
|
|
.erro {
|
|
color: var(--perigo);
|
|
}
|
|
</style>
|