Meta Description" name="description" />
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brazo Robotico v5.2 - Simulación</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #1a1a2e; color: #eee; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; justify-content: center; padding: 20px; }
.main-container { max-width: 650px; width: 100%; background: #16213e; border-radius: 20px; padding: 25px; box-shadow: 0 20px 40px rgba(0,0,0,0.6); }
h1 { text-align: center; margin-bottom: 20px; font-size: 1.8em; color: #e94560; }
.seccion { background: #0f3460; border-radius: 15px; padding: 20px; margin-bottom: 20px; box-shadow: 0 10px 20px rgba(0,0,0,0.3); }
.seccion h2 { font-size: 1.3em; margin-bottom: 15px; color: #f5f5f5; border-bottom: 2px solid #e94560; padding-bottom: 5px; }
canvas { display: block; margin: 0 auto; border: 3px solid #e94560; border-radius: 12px; box-shadow: 0 0 20px rgba(233, 69, 96, 0.5); max-width: 100%; height: auto; }
.info { display: flex; justify-content: space-between; margin: 10px 0; background: #1a1a2e; padding: 8px 12px; border-radius: 8px; flex-wrap: wrap; }
.info span { font-weight: bold; color: #e94560; }
button { background: #e94560; border: none; color: white; padding: 12px 15px; margin: 5px; border-radius: 25px; font-size: 0.9em; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 10px rgba(0,0,0,0.2); font-weight: bold; }
button:disabled { background: #555; color: #aaa; cursor: not-allowed; box-shadow: none; }
button:not(:disabled):hover { background: #c23152; transform: translateY(-2px); box-shadow: 0 8px 15px rgba(0,0,0,0.3); }
select { width: 100%; padding: 12px; border-radius: 25px; background: #1a1a2e; color: white; border: 2px solid #e94560; font-size: 1em; margin: 5px 0; }
.slider-container { margin: 15px 0; }
.slider-container label { display: flex; justify-content: space-between; margin-bottom: 5px; font-weight: bold; }
input[type=range] { width: 100%; height: 20px; -webkit-appearance: none; background: #0f3460; border-radius: 10px; outline: none; }
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 30px; height: 30px; background: #e94560; border-radius: 50%; cursor: pointer; box-shadow: 0 0 10px #e94560; }
.botones-accion { display: flex; flex-wrap: wrap; justify-content: center; }
#mensaje { color: #ff6b6b; font-weight: bold; text-align: center; margin-top: 10px; }
.btn-ajuste { width: 30px; height: 30px; padding: 0; font-size: 1.2em; background: #0f3460; }
.velocidad-selector { display: flex; justify-content: center; gap: 10px; margin-bottom: 15px; flex-wrap: wrap; }
.velocidad-selector label { display: flex; align-items: center; gap: 5px; cursor: pointer; }
.velocidad-selector input[type=radio] { display: none; }
.velocidad-selector .radio-btn { padding: 8px 15px; border-radius: 20px; background: #555; color: #ccc; cursor: pointer; transition: all 0.3s ease; font-size: 0.9em; }
.velocidad-selector input[type=radio]:checked + .radio-btn { background: #e94560; color: white; box-shadow: 0 0 15px rgba(233,69,96,0.5); }
.desplegable-container { background: #0a1a2e; border-radius: 15px; padding: 15px; margin: 10px 0; border: 1px solid #e94560; }
.desplegable-container p { margin-bottom: 10px; font-weight: bold; }
.desplegable-container select { background: #1a1a2e; }
</style>
</head>
<body>
<div class="main-container">
<h1>♟️ Brazo Robotico <small style="color:#aaa;">v5.2 Simulación</small></h1>
<div class="seccion">
<h2>🎯 Tablero de Ajedrez</h2>
<canvas id="chessboard" width="480" height="480"></canvas>
<div class="info">
<span>Turno: <b id="turnoActual">Blanco</b></span>
<span>Casilla: <b id="casillaSel">-</b></span>
<span>Pieza: <b id="piezaSel">-</b></span>
</div>
<div id="mensaje"></div>
<div class="botones-accion">
<button id="grabarBtn" disabled>💾 Grabar</button>
<button id="irBtn" disabled>▶️ Ir</button>
<button id="borrarBtn" disabled>🗑️ Borrar</button>
<button id="moverPiezaBtn" disabled>♟️ Mover pieza</button>
<button id="deshacerBtn">↩️ Deshacer</button>
<button id="rehacerBtn">↪️ Rehacer</button>
<button id="resetTableroBtn">🔄 Reset</button>
</div>
<div class="desplegable-container">
<p>📍 Casillas guardadas:</p>
<select id="selectPosiciones" onchange="seleccionarDesdeDesplegable()">
<option value="">-- Seleccionar casilla grabada --</option>
</select>
<div class="botones-accion" style="margin-top:10px;">
<button id="irDesdeDesplegable" disabled onclick="irDesdeDesplegable()">▶️ Ir a seleccionada</button>
<button id="borrarDesdeDesplegable" disabled onclick="borrarDesdeDesplegable()">🗑️ Borrar seleccionada</button>
</div>
</div>
</div>
<div class="seccion">
<h2>🎮 Control Manual</h2>
<div class="velocidad-selector">
<label><input type="radio" name="velocidad" value="suave" onchange="cambiarVelocidad('suave')"><span class="radio-btn">🐢 Suave</span></label>
<label><input type="radio" name="velocidad" value="medio" onchange="cambiarVelocidad('medio')" checked><span class="radio-btn">🐇 Medio</span></label>
<label><input type="radio" name="velocidad" value="rapido" onchange="cambiarVelocidad('rapido')"><span class="radio-btn">🚀 Rápido</span></label>
</div>
<div id="sliders"></div>
<div class="botones-accion">
<button onclick="alert('Reposo')">🧘 Reposo</button>
<button onclick="alert('Recoger')">🤏 Recoger (E2)</button>
<button onclick="alert('Soltar')">✋ Soltar (E4)</button>
</div>
</div>
<div class="seccion" id="seccionResolucion">
<h2>⚙️ Ajustes de Resolución (por canal)</h2>
<div class="slider-container">
<label>Seleccionar canal:</label>
<select id="selectCanal" onchange="cargarValoresCanal()">
<option value="0">Canal 0 - Base</option>
<option value="1">Canal 1 - Hombro</option>
<option value="2">Canal 2 - Codo</option>
<option value="3">Canal 3 - Muñeca Inc</option>
<option value="4">Canal 4 - Muñeca Giro</option>
<option value="5">Canal 5 - Pinza</option>
</select>
</div>
<div class="slider-container">
<label>Zona Muerta (µs): <span id="deadbandVal">5</span></label>
<input type="range" id="deadbandSlider" min="1" max="20" value="5" oninput="guardarDeadband(this.value)">
</div>
<div class="slider-container">
<label>Suavizado (delay ms): <span id="smoothVal">2</span></label>
<input type="range" id="smoothSlider" min="1" max="10" value="2" oninput="guardarSmooth(this.value)">
</div>
</div>
</div>
<script>
// --- LÓGICA DE SIMULACIÓN (v5.2 - Guardado por canal corregido) ---
(function() {
// Variables globales
let velocidadGlobal = 'medio';
let casillaSeleccionada = -1, piezaSeleccionada = -1;
let posicionesGrabadas = new Array(64).fill(false);
let turno = 'blanco';
let historial = [];
let indiceHistorial = -1;
let canalSeleccionado = 0;
// Arrays para deadband y smooth por canal (valores iniciales)
const deadbandPorCanal = [5, 5, 5, 5, 5, 5];
const smoothPorCanal = [2, 2, 2, 2, 2, 2];
const piezasIniciales = [
'r','n','b','q','k','b','n','r',
'p','p','p','p','p','p','p','p',
'','','','','','','','',
'','','','','','','','',
'','','','','','','','',
'','','','','','','','',
'P','P','P','P','P','P','P','P',
'R','N','B','Q','K','B','N','R'
];
let tablero = [...piezasIniciales];
// Funciones auxiliares
function esMayuscula(c) { return c >= 'A' && c <= 'Z'; }
function colorPieza(p) { return p ? (esMayuscula(p) ? 'blanco' : 'negro') : null; }
function esMovimientoValido(origen, destino, tablero, turno) {
const pieza = tablero[origen];
const captura = tablero[destino];
if (!pieza) return false;
if (colorPieza(pieza) !== turno) return false;
if (captura && colorPieza(captura) === turno) return false;
const filaO = Math.floor(origen / 8), colO = origen % 8;
const filaD = Math.floor(destino / 8), colD = destino % 8;
const difFil = filaD - filaO, difCol = colD - colO;
const tipo = pieza.toUpperCase();
function hayObstaculos(o, d, t) {
const fo = Math.floor(o/8), co = o%8, fd = Math.floor(d/8), cd = d%8;
const pf = Math.sign(fd - fo), pc = Math.sign(cd - co);
let f = fo + pf, c = co + pc;
while (f !== fd || c !== cd) { if (t[f*8+c] !== '') return true; f += pf; c += pc; }
return false;
}
switch (tipo) {
case 'P':
if (turno === 'blanco') {
if (difFil === -1 && difCol === 0 && !captura) return true;
if (filaO === 6 && difFil === -2 && difCol === 0 && !captura && !tablero[origen-8]) return true;
if (difFil === -1 && Math.abs(difCol) === 1 && captura && colorPieza(captura) === 'negro') return true;
} else {
if (difFil === 1 && difCol === 0 && !captura) return true;
if (filaO === 1 && difFil === 2 && difCol === 0 && !captura && !tablero[origen+8]) return true;
if (difFil === 1 && Math.abs(difCol) === 1 && captura && colorPieza(captura) === 'blanco') return true;
}
return false;
case 'R': return (difFil===0 || difCol===0) && !hayObstaculos(origen, destino, tablero);
case 'N': return (Math.abs(difFil)===2 && Math.abs(difCol)===1) || (Math.abs(difFil)===1 && Math.abs(difCol)===2);
case 'B': return Math.abs(difFil)===Math.abs(difCol) && !hayObstaculos(origen, destino, tablero);
case 'Q': return (difFil===0 || difCol===0 || Math.abs(difFil)===Math.abs(difCol)) && !hayObstaculos(origen, destino, tablero);
case 'K': return Math.abs(difFil)<=1 && Math.abs(difCol)<=1;
default: return false;
}
}
function guardarEstado() {
historial = historial.slice(0, indiceHistorial + 1);
historial.push({ tablero: [...tablero], turno });
indiceHistorial = historial.length - 1;
actualizarBotonesHistorial();
}
function deshacer() {
if (indiceHistorial > 0) {
indiceHistorial--;
const est = historial[indiceHistorial];
tablero = [...est.tablero];
turno = est.turno;
piezaSeleccionada = casillaSeleccionada = -1;
actualizarTodo();
dibujarTablero();
}
}
function rehacer() {
if (indiceHistorial < historial.length - 1) {
indiceHistorial++;
const est = historial[indiceHistorial];
tablero = [...est.tablero];
turno = est.turno;
piezaSeleccionada = casillaSeleccionada = -1;
actualizarTodo();
dibujarTablero();
}
}
function actualizarBotonesHistorial() {
document.getElementById('deshacerBtn').disabled = (indiceHistorial <= 0);
document.getElementById('rehacerBtn').disabled = (indiceHistorial >= historial.length - 1);
}
// Dibujo del tablero
const canvas = document.getElementById('chessboard');
const ctx = canvas.getContext('2d');
const size = 60;
function dibujarTablero() {
if (!ctx) return;
for (let row = 0; row < 8; row++) {
for (let col = 0; col < 8; col++) {
const idx = row * 8 + col;
ctx.fillStyle = (row + col) % 2 === 0 ? '#deb887' : '#8b5a2b';
ctx.fillRect(col * size, row * size, size, size);
if (posicionesGrabadas[idx]) {
ctx.fillStyle = 'rgba(0, 255, 0, 0.3)';
ctx.fillRect(col * size, row * size, size, size);
}
if (idx === casillaSeleccionada) {
ctx.strokeStyle = '#ff0'; ctx.lineWidth = 4;
ctx.strokeRect(col * size + 2, row * size + 2, size - 4, size - 4);
}
if (idx === piezaSeleccionada) {
ctx.strokeStyle = '#0ff'; ctx.lineWidth = 4;
ctx.strokeRect(col * size + 2, row * size + 2, size - 4, size - 4);
}
const pieza = tablero[idx];
if (pieza) {
ctx.fillStyle = pieza === pieza.toUpperCase() ? '#fff' : '#000';
ctx.font = 'bold 36px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const sim = { K:'\u2654',Q:'\u2655',R:'\u2656',B:'\u2657',N:'\u2658',P:'\u2659', k:'\u265A',q:'\u265B',r:'\u265C',b:'\u265D',n:'\u265E',p:'\u265F' };
ctx.fillText(sim[pieza], col * size + size/2, row * size + size/2);
}
ctx.fillStyle = (row + col) % 2 === 0 ? '#8b5a2b' : '#deb887';
ctx.font = 'bold 12px Arial';
ctx.textAlign = 'left';
if (col === 0) ctx.fillText(8 - row, 5, row * size + 18);
if (row === 7) ctx.fillText('abcdefgh'[col], col * size + 48, 476);
}
}
}
function actualizarTodo() {
document.getElementById('turnoActual').textContent = turno === 'blanco' ? 'Blanco' : 'Negro';
document.getElementById('casillaSel').textContent = casillaSeleccionada >= 0 ? 'abcdefgh'[casillaSeleccionada%8] + (8 - Math.floor(casillaSeleccionada/8)) : '-';
document.getElementById('piezaSel').textContent = piezaSeleccionada >= 0 ? 'abcdefgh'[piezaSeleccionada%8] + (8 - Math.floor(piezaSeleccionada/8)) : '-';
actualizarBotones();
actualizarBotonesHistorial();
}
function actualizarBotones() {
document.getElementById('grabarBtn').disabled = (casillaSeleccionada < 0);
document.getElementById('irBtn').disabled = (casillaSeleccionada < 0 || !posicionesGrabadas[casillaSeleccionada]);
document.getElementById('borrarBtn').disabled = (casillaSeleccionada < 0 || !posicionesGrabadas[casillaSeleccionada]);
document.getElementById('moverPiezaBtn').disabled = (piezaSeleccionada < 0 || casillaSeleccionada < 0 || piezaSeleccionada === casillaSeleccionada);
actualizarBotonesDesplegable();
}
function actualizarDesplegable() {
const select = document.getElementById('selectPosiciones');
select.innerHTML = '<option value="">-- Seleccionar casilla grabada --</option>';
for (let i = 0; i < 64; i++) {
if (posicionesGrabadas[i]) {
const casilla = 'abcdefgh'[i%8] + (8 - Math.floor(i/8));
select.innerHTML += '<option value="' + i + '">' + casilla + '</option>';
}
}
}
function actualizarBotonesDesplegable() {
document.getElementById('irDesdeDesplegable').disabled = (casillaSeleccionada < 0 || !posicionesGrabadas[casillaSeleccionada]);
document.getElementById('borrarDesdeDesplegable').disabled = (casillaSeleccionada < 0 || !posicionesGrabadas[casillaSeleccionada]);
}
// NUEVO: Cargar valores del canal seleccionado en los sliders
window.cargarValoresCanal = function() {
const select = document.getElementById('selectCanal');
canalSeleccionado = parseInt(select.value);
// Actualizar sliders con los valores guardados para este canal
document.getElementById('deadbandSlider').value = deadbandPorCanal[canalSeleccionado];
document.getElementById('smoothSlider').value = smoothPorCanal[canalSeleccionado];
document.getElementById('deadbandVal').textContent = deadbandPorCanal[canalSeleccionado];
document.getElementById('smoothVal').textContent = smoothPorCanal[canalSeleccionado];
};
// NUEVO: Guardar deadband en el array del canal actual
window.guardarDeadband = function(val) {
const valor = parseInt(val);
deadbandPorCanal[canalSeleccionado] = valor;
document.getElementById('deadbandVal').textContent = valor;
};
// NUEVO: Guardar smooth en el array del canal actual
window.guardarSmooth = function(val) {
const valor = parseInt(val);
smoothPorCanal[canalSeleccionado] = valor;
document.getElementById('smoothVal').textContent = valor;
};
// Eventos de la interfaz
window.seleccionarDesdeDesplegable = function() {
const select = document.getElementById('selectPosiciones');
const val = select.value;
if (val !== '') {
casillaSeleccionada = parseInt(val);
document.getElementById('casillaSel').textContent = 'abcdefgh'[casillaSeleccionada%8] + (8 - Math.floor(casillaSeleccionada/8));
actualizarBotones();
dibujarTablero();
} else {
casillaSeleccionada = -1;
document.getElementById('casillaSel').textContent = '-';
actualizarBotones();
dibujarTablero();
}
};
window.irDesdeDesplegable = function() {
if (casillaSeleccionada >= 0 && posicionesGrabadas[casillaSeleccionada]) {
alert('Moviendo a ' + 'abcdefgh'[casillaSeleccionada%8] + (8 - Math.floor(casillaSeleccionada/8)));
}
};
window.borrarDesdeDesplegable = function() {
if (casillaSeleccionada >= 0 && posicionesGrabadas[casillaSeleccionada]) {
posicionesGrabadas[casillaSeleccionada] = false;
actualizarBotones();
actualizarDesplegable();
dibujarTablero();
}
};
window.cambiarVelocidad = function(nueva) {
velocidadGlobal = nueva;
console.log('Velocidad simulada: ' + nueva);
};
// Crear sliders
const nombresServos = ['Base', 'Hombro', 'Codo', 'Muñeca Inc', 'Muñeca Giro', 'Pinza'];
function crearSliders() {
const container = document.getElementById('sliders');
nombresServos.forEach(function(nombre, i) {
const div = document.createElement('div');
div.className = 'slider-container';
div.innerHTML =
'<label>' + nombre + ': <span id="valor' + i + '">90</span>°</label><br>' +
'<div style="display:flex; align-items:center; gap:5px;">' +
'<button class="btn-ajuste" onclick="window.ajustarPaso(' + i + ', -1)">−</button>' +
'<input type="range" min="0" max="180" value="90" style="flex:1;" id="slider' + i + '" ' +
'oninput="window.moverSlider(' + i + ', this.value)">' +
'<button class="btn-ajuste" onclick="window.ajustarPaso(' + i + ', 1)">+</button>' +
'</div>';
container.appendChild(div);
});
}
window.ajustarPaso = function(canal, delta) {
const slider = document.getElementById('slider' + canal);
let nuevoAngulo = parseInt(slider.value) + delta;
nuevoAngulo = Math.max(0, Math.min(180, nuevoAngulo));
slider.value = nuevoAngulo;
document.getElementById('valor' + canal).textContent = nuevoAngulo;
};
window.moverSlider = function(canal, valor) {
document.getElementById('valor' + canal).textContent = valor;
};
// Eventos de botones
document.getElementById('grabarBtn').addEventListener('click', function() {
if (casillaSeleccionada >= 0) {
posicionesGrabadas[casillaSeleccionada] = true;
actualizarBotones();
actualizarDesplegable();
dibujarTablero();
}
});
document.getElementById('irBtn').addEventListener('click', function() {
if (casillaSeleccionada >= 0 && posicionesGrabadas[casillaSeleccionada]) {
alert('Moviendo a ' + 'abcdefgh'[casillaSeleccionada%8] + (8 - Math.floor(casillaSeleccionada/8)));
}
});
document.getElementById('borrarBtn').addEventListener('click', function() {
if (casillaSeleccionada >= 0 && posicionesGrabadas[casillaSeleccionada]) {
posicionesGrabadas[casillaSeleccionada] = false;
actualizarBotones();
actualizarDesplegable();
dibujarTablero();
}
});
document.getElementById('moverPiezaBtn').addEventListener('click', function() {
if (piezaSeleccionada >= 0 && casillaSeleccionada >= 0 && casillaSeleccionada !== piezaSeleccionada) {
if (esMovimientoValido(piezaSeleccionada, casillaSeleccionada, tablero, turno)) {
guardarEstado();
tablero[casillaSeleccionada] = tablero[piezaSeleccionada];
tablero[piezaSeleccionada] = '';
turno = turno === 'blanco' ? 'negro' : 'blanco';
piezaSeleccionada = casillaSeleccionada = -1;
actualizarTodo();
dibujarTablero();
} else {
document.getElementById('mensaje').textContent = '⛔ Movimiento no válido o no es tu turno.';
}
}
});
document.getElementById('resetTableroBtn').addEventListener('click', function() {
tablero = [...piezasIniciales];
turno = 'blanco';
piezaSeleccionada = casillaSeleccionada = -1;
historial = []; indiceHistorial = -1;
guardarEstado();
actualizarTodo();
dibujarTablero();
});
document.getElementById('deshacerBtn').addEventListener('click', deshacer);
document.getElementById('rehacerBtn').addEventListener('click', rehacer);
canvas.addEventListener('click', function(e) {
const rect = canvas.getBoundingClientRect();
const col = Math.floor((e.clientX - rect.left) / size);
const row = Math.floor((e.clientY - rect.top) / size);
if (col < 0 || col > 7 || row < 0 || row > 7) return;
const idx = row * 8 + col;
const pieza = tablero[idx];
document.getElementById('mensaje').textContent = '';
if (piezaSeleccionada >= 0) {
if (idx === piezaSeleccionada) {
piezaSeleccionada = -1; casillaSeleccionada = idx;
} else if (pieza && colorPieza(pieza) === colorPieza(tablero[piezaSeleccionada])) {
piezaSeleccionada = idx; casillaSeleccionada = -1;
} else {
casillaSeleccionada = idx;
}
} else {
casillaSeleccionada = idx;
if (pieza && colorPieza(pieza) === turno) piezaSeleccionada = idx;
}
if (posicionesGrabadas[idx]) {
document.getElementById('selectPosiciones').value = idx;
actualizarBotonesDesplegable();
} else {
document.getElementById('selectPosiciones').value = '';
actualizarBotonesDesplegable();
}
actualizarTodo();
dibujarTablero();
});
// Inicialización final
crearSliders();
dibujarTablero();
guardarEstado();
actualizarTodo();
})();
</script>
</body>
</html>1
1
23KB
23KB
193.0ms
216.0ms
194.0ms