Encoder
<div style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;">
<h1 style="color: #007bff;">Velocímetro con acelerómetro 📱</h1>
<div style="font-size: 1.5em; margin: 10px 0;">Velocidad X: <span id="vx">0</span> m/s</div>
<div style="font-size: 1.5em; margin: 10px 0;">Velocidad Y: <span id="vy">0</span> m/s</div>
<div style="font-size: 1.5em; margin: 10px 0;">Velocidad Z: <span id="vz">0</span> m/s</div>
<div style="font-size: 1.5em; margin: 10px 0;"><strong>Velocidad Máxima: <span id="vmax">0</span> m/s</strong></div>
<button id="startBtn" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar medición</button> <button id="resetBtn" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button>
<div id="status" style="color: #555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div>
</div>
<p><script>
let lastTimestamp = null;
let vx = 0, vy = 0, vz = 0;
let vmax = 0;
let gx = 0, gy = 0, gz = 0;
const alpha = 0.8;
const statusEl = document.getElementById("status");
function setStatus(msg) {
statusEl.textContent = msg;
console.log(msg);
}
function updateDisplay() {
document.getElementById("vx").textContent = vx.toFixed(2);
document.getElementById("vy").textContent = vy.toFixed(2);
document.getElementById("vz").textContent = vz.toFixed(2);
document.getElementById("vmax").textContent = vmax.toFixed(2);
}
function resetValues() {
vx = vy = vz = vmax = 0;
gx = gy = gz = 0;
lastTimestamp = null;
updateDisplay();
setStatus("🔄 Reiniciado");
}
function startMotion() {
if (typeof DeviceMotionEvent === 'undefined') {
setStatus("❌ Tu navegador no soporta DeviceMotionEvent.");
return;
}
// iOS (por compatibilidad futura) o Android modernos
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(response => {
if (response === 'granted') {
setStatus("✅ Permiso concedido. Mueve el móvil.");
window.addEventListener('devicemotion', motionHandler);
} else {
setStatus("❌ Permiso denegado: " + response);
}
})
.catch(err => setStatus("⚠️ Error solicitando permiso: " + err));
} else {
// Android normalmente entra aquí
setStatus("✅ Sensor activado. Mueve el móvil.");
window.addEventListener('devicemotion', motionHandler);
}
}
function motionHandler(event) {
const acc = event.accelerationIncludingGravity;
const ts = event.timeStamp;
if (!acc) {
setStatus("⚠️ No se reciben datos de aceleración");
return;
}
if (lastTimestamp === null) {
lastTimestamp = ts;
return;
}
// Filtro pasa-alto para quitar gravedad
gx = alpha * gx + (1 - alpha) * acc.x;
gy = alpha * gy + (1 - alpha) * acc.y;
gz = alpha * gz + (1 - alpha) * acc.z;
const ax = acc.x - gx;
const ay = acc.y - gy;
const az = acc.z - gz;
const dt = (ts - lastTimestamp) / 1000;
lastTimestamp = ts;
vx += ax * dt;
vy += ay * dt;
vz += az * dt;
const maxAxis = Math.max(Math.abs(vx), Math.abs(vy), Math.abs(vz));
if (maxAxis > vmax) vmax = maxAxis;
updateDisplay();
}
document.getElementById('startBtn').addEventListener('click', startMotion);
document.getElementById('resetBtn').addEventListener('click', resetValues);
</script></p>
Enplo
<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;">
<h1 style="color:#007BFF;">Encoder de velocidad 📊</h1>
<div style="font-size: 1.5em; margin: 10px 0;">
Velocidad actual: <span id="velocidad">0.00</span> m/s
</div>
<div style="font-size: 2em; margin: 10px 0;">
🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong>
</div>
<button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button>
<button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button>
<div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div>
</div>
<script>
// Esperamos a que la página cargue completamente (importante en WordPress)
document.addEventListener('DOMContentLoaded', function () {
let lastTimestamp = null;
let velocidad = 0;
let vmax = 0;
let gz = 0;
const alpha = 0.8;
const UMBRAL_ACEL = 0.2;
const velSpan = document.getElementById("velocidad");
const vmaxSpan = document.getElementById("vmax");
const statusEl = document.getElementById("status");
const startBtn = document.getElementById("startBtn");
const resetBtn = document.getElementById("resetBtn");
function setStatus(msg) {
statusEl.textContent = msg;
console.log(msg);
}
function updateDisplay() {
velSpan.textContent = velocidad.toFixed(2);
vmaxSpan.textContent = vmax.toFixed(2);
}
function resetValues() {
velocidad = 0;
vmax = 0;
gz = 0;
lastTimestamp = null;
updateDisplay();
setStatus("🔄 Reiniciado");
}
function startMotion() {
if (typeof DeviceMotionEvent === 'undefined') {
setStatus("❌ Tu navegador no soporta DeviceMotionEvent.");
return;
}
// Android: no necesita permisos normalmente
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(response => {
if (response === 'granted') {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
} else {
setStatus("❌ Permiso denegado: " + response);
}
})
.catch(err => setStatus("⚠️ Error: " + err));
} else {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
}
}
function motionHandler(event) {
const acc = event.accelerationIncludingGravity;
const ts = event.timeStamp;
if (!acc) return;
if (lastTimestamp === null) {
lastTimestamp = ts;
return;
}
// Filtro pasa-alto para eliminar la gravedad
gz = alpha * gz + (1 - alpha) * acc.z;
const az = acc.z - gz;
const dt = (ts - lastTimestamp) / 1000;
lastTimestamp = ts;
// Integramos solo si hay movimiento real
if (Math.abs(az) > UMBRAL_ACEL) {
velocidad += az * dt;
if (Math.abs(velocidad) > vmax) vmax = Math.abs(velocidad);
} else {
// Reducción de deriva cuando está en reposo
velocidad *= 0.98;
}
updateDisplay();
}
startBtn.addEventListener('click', startMotion);
resetBtn.addEventListener('click', resetValues);
});
</script>
Enco
<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;">
<h1 style="color:#007BFF;">Encoder de velocidad 📊</h1>
<div style="font-size: 1.5em; margin: 10px 0;">
Velocidad actual: <span id="velocidad">0.00</span> m/s
</div>
<div style="font-size: 2em; margin: 10px 0;">
🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong>
</div>
<button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button>
<button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button>
<div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div>
</div>
<script>
// Esperamos a que la página cargue completamente (importante en WordPress)
document.addEventListener('DOMContentLoaded', function () {
let lastTimestamp = null;
let velocidad = 0;
let vmax = 0;
let gz = 0;
const alpha = 0.8;
const UMBRAL_ACEL = 0.2;
const velSpan = document.getElementById("velocidad");
const vmaxSpan = document.getElementById("vmax");
const statusEl = document.getElementById("status");
const startBtn = document.getElementById("startBtn");
const resetBtn = document.getElementById("resetBtn");
function setStatus(msg) {
statusEl.textContent = msg;
console.log(msg);
}
function updateDisplay() {
velSpan.textContent = velocidad.toFixed(2);
vmaxSpan.textContent = vmax.toFixed(2);
}
function resetValues() {
velocidad = 0;
vmax = 0;
gz = 0;
lastTimestamp = null;
updateDisplay();
setStatus("🔄 Reiniciado");
}
function startMotion() {
if (typeof DeviceMotionEvent === 'undefined') {
setStatus("❌ Tu navegador no soporta DeviceMotionEvent.");
return;
}
// Android: no necesita permisos normalmente
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(response => {
if (response === 'granted') {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
} else {
setStatus("❌ Permiso denegado: " + response);
}
})
.catch(err => setStatus("⚠️ Error: " + err));
} else {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
}
}
function motionHandler(event) {
const acc = event.accelerationIncludingGravity;
const ts = event.timeStamp;
if (!acc) return;
if (lastTimestamp === null) {
lastTimestamp = ts;
return;
}
// Filtro pasa-alto para eliminar la gravedad
gz = alpha * gz + (1 - alpha) * acc.z;
const az = acc.z - gz;
const dt = (ts - lastTimestamp) / 1000;
lastTimestamp = ts;
// Integramos solo si hay movimiento real
if (Math.abs(az) > UMBRAL_ACEL) {
velocidad += az * dt;
if (Math.abs(velocidad) > vmax) vmax = Math.abs(velocidad);
} else {
// Reducción de deriva cuando está en reposo
velocidad *= 0.98;
}
updateDisplay();
}
startBtn.addEventListener('click', startMotion);
resetBtn.addEventListener('click', resetValues);
});
</script>
EMo
<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;">
<h1 style="color:#007BFF;">Encoder de velocidad 📊</h1>
<div style="font-size: 1.5em; margin: 10px 0;">
Velocidad actual: <span id="velocidad">0.00</span> m/s
</div>
<div style="font-size: 2em; margin: 10px 0;">
🏁 <strong>Velocidad Máxima: <span id="vmax">0.00</span> m/s</strong>
</div>
<button id="startBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Iniciar</button>
<button id="resetBtn" type="button" style="padding: 10px 20px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 5px;">Reiniciar</button>
<div id="status" style="color:#555; margin-top: 15px; font-size: 0.9em;">⏸ Aún no iniciado</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
let lastTimestamp = null;
let velocidad = 0;
let vmax = 0;
let gz = 0;
const alpha = 0.8;
const UMBRAL_ACEL = 0.2;
const VMIN_RESET = 0.05; // debajo de esto consideramos que la barra se detuvo
const velSpan = document.getElementById("velocidad");
const vmaxSpan = document.getElementById("vmax");
const statusEl = document.getElementById("status");
const startBtn = document.getElementById("startBtn");
const resetBtn = document.getElementById("resetBtn");
function setStatus(msg) {
statusEl.textContent = msg;
console.log(msg);
}
function updateDisplay() {
velSpan.textContent = velocidad.toFixed(2);
vmaxSpan.textContent = vmax.toFixed(2);
}
function resetValues() {
velocidad = 0;
vmax = 0;
gz = 0;
lastTimestamp = null;
updateDisplay();
setStatus("🔄 Reiniciado");
}
function startMotion() {
if (typeof DeviceMotionEvent === 'undefined') {
setStatus("❌ Tu navegador no soporta DeviceMotionEvent.");
return;
}
if (typeof DeviceMotionEvent.requestPermission === 'function') {
DeviceMotionEvent.requestPermission()
.then(response => {
if (response === 'granted') {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
} else {
setStatus("❌ Permiso denegado: " + response);
}
})
.catch(err => setStatus("⚠️ Error: " + err));
} else {
setStatus("✅ Sensor activado. Coloca el móvil sobre la carga.");
window.addEventListener('devicemotion', motionHandler);
}
}
function motionHandler(event) {
const acc = event.accelerationIncludingGravity;
const ts = event.timeStamp;
if (!acc) return;
if (lastTimestamp === null) {
lastTimestamp = ts;
return;
}
// Filtro pasa-alto para eliminar la gravedad
gz = alpha * gz + (1 - alpha) * acc.z;
const az = acc.z - gz;
const dt = (ts - lastTimestamp) / 1000;
lastTimestamp = ts;
// Integramos solo si hay movimiento real
if (Math.abs(az) > UMBRAL_ACEL) {
velocidad += az * dt;
} else {
// desacelera suavemente si no hay movimiento
velocidad *= 0.98;
}
// Guardar el pico máximo alcanzado
const absVel = Math.abs(velocidad);
if (absVel > vmax) {
vmax = absVel;
}
// Si velocidad baja casi a cero, dejamos el valor máximo fijo
if (absVel < VMIN_RESET) {
velocidad = 0;
}
updateDisplay();
}
startBtn.addEventListener('click', startMotion);
resetBtn.addEventListener('click', resetValues);
});
</script>
orr
<div id="encoder-motionis" style="font-family: Arial, sans-serif; text-align: center; background: #f5f8fa; padding: 30px;">
<h1 style="color:#007BFF;">Encoder de velocidad 📊</h1>
<div style="font-size: 1.2em; margin: 6px 0;">Velocidad X: <span id="vx">0.00</span> m/s</div>
<div style="font-size: 1.2em; margin: 6px 0;">Velocidad Y: <span id="vy">0.00</span> m/s</div>
<div style="font-size: 1.2em; margin: 6px 0;">Velocidad Z: <span id="vz">0.00</span> m/s</div>
<!-- vmax grande y muy visible -->
<div style="font-size: 3rem; font-weight: 800; color: #FF4500; margin: 18px 0; line-height: 1;">
🏁 <span id="vmax">0.00</span> m/s
</div>
<button id="startBtn" type="button" style="padding: 12px 22px; font-size: 1em; background: #007BFF; color: white; border: none; border-radius: 10px; cursor: pointer; margin: 6px;">Iniciar</button>
<button id="resetBtn" type="button" style="padding: 12px 22px; font-size: 1em; background: #6c757d; color: white; border: none; border-radius: 10px; cursor: pointer; margin: 6px;">Reiniciar</button>
<div id="status" style="color:#555; margin-top: 12px; font-size: 0.95em;">⏸ Aún no iniciado</div>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
// Estado
const statusEl = document.getElementById('status');
const vxEl = document.getElementById('vx');
const vyEl = document.getElementById('vy');
const vzEl = document.getElementById('vz');
const vmaxEl = document.getElementById('vmax');
const startBtn = document.getElementById('startBtn');
const resetBtn = document.getElementById('resetBtn');
// Variables físicas
let lastTs = null;
let vx = 0, vy = 0, vz = 0;
let vmax = 0;
// Filtro pasa-alto para quitar gravedad cuando usamos accelerationIncludingGravity
let gx = 0, gy = 0, gz = 0;
const alpha = 0.8; // suavizado del filtro pasa-alto
const ACC_THRESHOLD = 0.20; // m/s²: umbral para ignorar ruido
const DECAY = 0.97; // reducción suave en reposo para frenar deriva
const MIN_SPEED = 0.05; // por debajo de esto, fuerza a 0
let usingIncluding = null; // decidimos automáticamente qué campo usar en el primer evento
function setStatus(msg){ statusEl.textContent = msg; console.log(msg); }
function updateUI(){
vxEl.textContent = vx.toFixed(2);
vyEl.textContent = vy.toFixed(2);
vzEl.textContent = vz.toFixed(2);
vmaxEl.textContent = vmax.toFixed(2);
}
function resetAll(){
lastTs = null;
vx = vy = vz = 0;
vmax = 0;
gx = gy = gz = 0;
usingIncluding = null;
updateUI();
setStatus('🔄 Reiniciado');
}
function startMotion(){
if (typeof DeviceMotionEvent === 'undefined'){
setStatus('❌ DeviceMotionEvent no soportado en este navegador.');
return;
}
// iOS pediría permiso; en Android normalmente no hace falta:
if (typeof DeviceMotionEvent.requestPermission === 'function'){
DeviceMotionEvent.requestPermission()
.then(r => {
if (r === 'granted'){
setStatus('✅ Sensor activado. Coloca el móvil y realiza la repetición.');
window.addEventListener('devicemotion', onMotion, { passive: true });
} else {
setStatus('❌ Permiso denegado: ' + r);
}
})
.catch(err => setStatus('⚠️ Error permiso: ' + err));
} else {
setStatus('✅ Sensor activado. Coloca el móvil y realiza la repetición.');
window.addEventListener('devicemotion', onMotion, { passive: true });
}
}
function onMotion(ev){
// Elegimos la mejor fuente disponible AUTOMÁTICAMENTE en el 1er evento
if (usingIncluding === null){
if (ev.acceleration && ev.acceleration.x !== null){
usingIncluding = false; // ya viene sin gravedad
setStatus('📡 usando event.acceleration (sin gravedad)');
} else {
usingIncluding = true; // usaremos includingGravity + filtro pasa-alto
setStatus('📡 usando accelerationIncludingGravity + filtro');
}
}
const ts = ev.timeStamp;
if (lastTs === null){ lastTs = ts; return; }
const dt = (ts - lastTs) / 1000;
lastTs = ts;
if (dt <= 0 || dt > 1) return; // evita saltos extraños
// Obtención de aceleraciones ax, ay, az en m/s²
let ax, ay, az;
if (!usingIncluding){
// Ya viene sin gravedad
const a = ev.acceleration;
if (!a) return;
ax = a.x || 0; ay = a.y || 0; az = a.z || 0;
} else {
// Quitamos gravedad mediante filtro pasa-alto
const ag = ev.accelerationIncludingGravity;
if (!ag) return;
gx = alpha * gx + (1 - alpha) * (ag.x || 0);
gy = alpha * gy + (1 - alpha) * (ag.y || 0);
gz = alpha * gz + (1 - alpha) * (ag.z || 0);
ax = (ag.x || 0) - gx;
ay = (ag.y || 0) - gy;
az = (ag.z || 0) - gz;
}
// Integramos solo si supera umbral (ignorar micro-ruido)
vx = (Math.abs(ax) > ACC_THRESHOLD) ? (vx + ax * dt) : (vx * DECAY);
vy = (Math.abs(ay) > ACC_THRESHOLD) ? (vy + ay * dt) : (vy * DECAY);
vz = (Math.abs(az) > ACC_THRESHOLD) ? (vz + az * dt) : (vz * DECAY);
// Corte bajo para forzar a 0 si queda residuo
if (Math.abs(vx) < MIN_SPEED) vx = 0;
if (Math.abs(vy) < MIN_SPEED) vy = 0;
if (Math.abs(vz) < MIN_SPEED) vz = 0;
// Actualizamos vmax (pico en cualquier eje, valor absoluto)
const maxAxis = Math.max(Math.abs(vx), Math.abs(vy), Math.abs(vz));
if (maxAxis > vmax) vmax = maxAxis;
updateUI();
}
startBtn.addEventListener('click', startMotion);
resetBtn.addEventListener('click', resetAll);
});
</script>