diff --git a/main/Javascript/record.js b/main/Javascript/record.js index 171aa7e..9203d91 100644 --- a/main/Javascript/record.js +++ b/main/Javascript/record.js @@ -4,6 +4,7 @@ window.addEventListener('DOMContentLoaded', function() { // 录制相关全局变量 window.isRecording = false; + window.isPlaying = false; window.recordedActions = []; window.recordingStartTime = 0; @@ -21,6 +22,11 @@ window.addEventListener('DOMContentLoaded', function() { // 录制按钮点击事件 - 支持鼠标和触摸事件 function toggleRecording() { console.log('toggleRecording called, current isRecording:', window.isRecording); + if (window.isPlaying) { + alert('正在回放,不能录制'); + return; + } + if (window.isRecording) { // 停止录制 window.isRecording = false; @@ -52,6 +58,11 @@ window.addEventListener('DOMContentLoaded', function() { // 回放按钮点击事件 - 支持鼠标和触摸事件 function startPlayback() { console.log('startPlayback called, recordedActions:', window.recordedActions); + if (window.isRecording) { + alert('请先停止录制'); + return; + } + if (window.recordedActions.length === 0) { status.innerHTML = `
没有可回放的操作
`; console.log('No actions to playback'); @@ -61,32 +72,35 @@ window.addEventListener('DOMContentLoaded', function() { // 保存当前录制状态并禁用录制 const originalRecordingState = window.isRecording; window.isRecording = false; + window.isPlaying = true; status.innerHTML = `开始回放...
`; console.log('Starting playback'); // 按时间顺序回放操作 - let lastTimestamp = 0; + let currentTime = 0; const totalDuration = window.recordedActions[window.recordedActions.length - 1].timestamp; - // 确保至少有一个操作 - if (window.recordedActions.length > 0) { - // 执行第一个操作 - console.log('Executing first action immediately:', window.recordedActions[0]); - controlMotor(window.recordedActions[0].direction); - - // 执行剩余的操作 - for (let i = 1; i < window.recordedActions.length; i++) { - const action = window.recordedActions[i]; - const delay = action.timestamp - window.recordedActions[i-1].timestamp; - console.log('Scheduling action:', action, 'at delay:', delay); + // 执行所有操作 + window.recordedActions.forEach((action, index) => { + if (index === 0) { + // 第一个操作立即执行 + console.log('Executing action immediately:', action); + controlMotor(action.direction); + } else { + // 计算与前一个操作的时间差 + const prevAction = window.recordedActions[index - 1]; + const delay = action.timestamp - prevAction.timestamp; + currentTime += delay; + + console.log('Scheduling action:', action, 'at delay:', currentTime); setTimeout(() => { // 调用控制函数执行操作 console.log('Executing action:', action); controlMotor(action.direction); - }, delay); + }, currentTime); } - } + }); // 回放完成后,确保发送停止请求 setTimeout(() => { @@ -96,7 +110,8 @@ window.addEventListener('DOMContentLoaded', function() { console.log('Playback completed'); // 恢复原始录制状态 window.isRecording = originalRecordingState; - }, totalDuration + 1000); + window.isPlaying = false; + }, totalDuration + 2000); // 增加延迟,确保所有动作都已执行 } console.log('Adding click event listener to playbackBtn'); diff --git a/main/motor_test.py b/main/motor_test.py new file mode 100644 index 0000000..4e7f65b --- /dev/null +++ b/main/motor_test.py @@ -0,0 +1,146 @@ +from smbus2 import SMBus +import time +import signal +import sys + +# ====================== +# Ctrl+C 安全退出 +# ====================== +def signal_handler(sig, frame): + print("\n停止电机...") + stop() + sys.exit(0) + +signal.signal(signal.SIGINT, signal_handler) + +# ====================== +# PCA9685 初始化 +# ====================== +bus = SMBus(1) +addr = 0x60 + +bus.write_byte_data(addr, 0x00, 0x00) +bus.write_byte_data(addr, 0xFE, 60) + +# ====================== +# 电机定义 +# ====================== +MOTOR = { + "M1": (0, 1), # 前左(Y轴) + "M2": (2, 3), # 前右(Y轴) + "M3": (4, 5), # 后左(X轴) + "M4": (6, 7), # 后右(X轴) +} + +# ⚠️ 需要你微调方向(如果反了就改 ±1) +DIR = { + "M1": 1, + "M2": 1, + "M3": 1, + "M4": 1, +} + +# ====================== +# PWM输出 +# ====================== +def set_pwm(ch, value): + value = max(0, min(4095, value)) + bus.write_byte_data(addr, 0x06 + 4 * ch, 0) + bus.write_byte_data(addr, 0x07 + 4 * ch, 0) + bus.write_byte_data(addr, 0x08 + 4 * ch, value & 0xFF) + bus.write_byte_data(addr, 0x09 + 4 * ch, value >> 8) + +# ====================== +# 单电机控制 +# ====================== +def motor_drive(name, speed): + in1, in2 = MOTOR[name] + + speed *= DIR[name] + pwm = int(abs(speed) * 4095) + + if speed > 0: + set_pwm(in1, pwm) + set_pwm(in2, 0) + elif speed < 0: + set_pwm(in1, 0) + set_pwm(in2, pwm) + else: + # 刹车 + set_pwm(in1, 4095) + set_pwm(in2, 4095) + +# ====================== +# ⭐ 全向轮核心控制(重点) +# vx: 左右 (-1~1) +# vy: 前后 (-1~1) +# w : 旋转 (-1~1) +# ====================== +def move(vx, vy, w): + m1 = vy + w + m2 = vy - w + m3 = vx + w + m4 = vx - w + + # 归一化(防止超限) + max_val = max(abs(m1), abs(m2), abs(m3), abs(m4), 1) + + motor_drive("M1", m1 / max_val) + motor_drive("M2", m2 / max_val) + motor_drive("M3", m3 / max_val) + motor_drive("M4", m4 / max_val) + +# ====================== +# 基础动作(封装) +# ====================== +def forward(speed=0.6): + move(0, speed, 0) + +def backward(speed=0.6): + move(0, -speed, 0) + +def left(speed=0.6): + move(-speed, 0, 0) + +def right(speed=0.6): + move(speed, 0, 0) + +def rotate_left(speed=0.6): + move(0, 0, speed) + +def rotate_right(speed=0.6): + move(0, 0, -speed) + +def stop(): + motor_drive("M1", 0) + motor_drive("M2", 0) + motor_drive("M3", 0) + motor_drive("M4", 0) + +# ====================== +# 测试 +# ====================== +if __name__ == "__main__": + + print("前进") + forward() + time.sleep(1) + + print("后退") + backward() + time.sleep(1) + + print("左移") + left() + time.sleep(1) + + print("右移") + right() + time.sleep(1) + + print("左旋转") + rotate_left() + time.sleep(1) + + print("停止") + stop() \ No newline at end of file