修改pwm控制口,优化测试线程,新增摸头按键事件

This commit is contained in:
peng 2025-08-04 15:49:13 +08:00
parent 69fdf9f026
commit 5cba58a334
3 changed files with 175 additions and 34 deletions

View File

@ -1,9 +1,7 @@
package com.ismart.ib86.app; package com.ismart.ib86.app;
import android.Manifest; import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Color;
import android.media.AudioAttributes; import android.media.AudioAttributes;
import android.media.AudioFormat; import android.media.AudioFormat;
import android.media.AudioManager; import android.media.AudioManager;
@ -13,7 +11,7 @@ import android.media.MediaRecorder;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.view.KeyEvent;
import android.view.Window; import android.view.Window;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.WindowInsetsController; import android.view.WindowInsetsController;
@ -22,7 +20,6 @@ import android.view.View;
import android.util.Log; import android.util.Log;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -32,14 +29,10 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol; import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
import com.ismart.ib86.feature.serial.SerialPort.SerialPortHelper;
import com.ismart.ib86.feature.gpio.GpioManager; import com.ismart.ib86.feature.gpio.GpioManager;
import com.ismart.ib86.feature.serial.SerialPort.ASR5515DeviceManager; import com.ismart.ib86.feature.serial.SerialPort.ASR5515DeviceManager;
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
import com.ismart.ib86.common.utils.LogManager; import com.ismart.ib86.common.utils.LogManager;
import com.ismart.ib86.feature.gpio.GpioTest;
import com.ismart.ib86.feature.motor.MotorController; import com.ismart.ib86.feature.motor.MotorController;
import com.ismart.ib86.view.RobotEyesView;
import com.lhht.xiaozhi.models.websokcet.send.WebSocketSendMsgFactory; import com.lhht.xiaozhi.models.websokcet.send.WebSocketSendMsgFactory;
import com.lhht.xiaozhi.settings.SettingsManager; import com.lhht.xiaozhi.settings.SettingsManager;
import com.lhht.xiaozhi.utils.DeviceUtils; import com.lhht.xiaozhi.utils.DeviceUtils;
@ -52,9 +45,11 @@ import java.util.concurrent.Executors;
import vip.inode.demo.opusaudiodemo.utils.OpusUtils; import vip.inode.demo.opusaudiodemo.utils.OpusUtils;
public class MainActivity extends AppCompatActivity implements WebSocketManager.WebSocketListener{ public class MainActivity extends AppCompatActivity implements WebSocketManager.WebSocketListener {
private static final String TAG = "MainActivity"; private static final String TAG = "MainActivity";
private static final String DEVICE_PATH = "/dev/ttyS3"; private static final String DEVICE_PATH = "/dev/ttyS3";
private static final int HEAD_TOUCH_KEY = 285;
private static final int BAUD_RATE = 921600; private static final int BAUD_RATE = 921600;
// 权限请求码 // 权限请求码
@ -95,6 +90,7 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
private short[] decodedBuffer; private short[] decodedBuffer;
private short[] recordBuffer; private short[] recordBuffer;
private byte[] encodedBuffer; private byte[] encodedBuffer;
private boolean hasStartedCall = false; private boolean hasStartedCall = false;
private boolean isRecording = false; private boolean isRecording = false;
private volatile boolean isDestroyed = false; private volatile boolean isDestroyed = false;
@ -102,17 +98,25 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
private boolean isPlaying = false; private boolean isPlaying = false;
private String sessionId = ""; // 添加session_id字段 private String sessionId = ""; // 添加session_id字段
private long lastAudioDataTime = 0; // 新增记录最后一次收到音频数据的时间 private long lastAudioDataTime = 0; // 新增记录最后一次收到音频数据的时间
private Thread motorControlThread; // 用于跟踪电机控制线程
private boolean isCheckingPlaybackStatus = false; private boolean isCheckingPlaybackStatus = false;
//xiaozhi end //xiaozhi end
// HeadTouchManager removed
// UI控件 // UI控件
private ImageView ivFace; private ImageView ivFace;
private Button btnRotateForward;
private Button btnRotateReverse;
private SeekBar seekBarDutyCycle;
private TextView tvDutyCycleValue;
private int currentDutyCyclePercent = 30; // 默认占空比30%
private static final int PWM_PERIOD = 1000000; // 1ms周期
// 动画管理器 // 动画管理器
private RobotFaceAnimationManager animationManager; private RobotFaceAnimationManager animationManager;
private boolean isCalibrating = false;
private boolean isForwardCalibration = false;
private boolean isReverseCalibration = false;
private Runnable wearDetectionRunnable = new Runnable() { private Runnable wearDetectionRunnable = new Runnable() {
@Override @Override
@ -131,6 +135,43 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
// 初始化UI控件 // 初始化UI控件
ivFace = (ImageView) this.findViewById(R.id.iv_face); ivFace = (ImageView) this.findViewById(R.id.iv_face);
// btnRotateForward = (Button) this.findViewById(R.id.btn_rotate_forward);
// btnRotateReverse = (Button) this.findViewById(R.id.btn_rotate_reverse);
// seekBarDutyCycle = (SeekBar) this.findViewById(R.id.seekbar_duty_cycle);
// tvDutyCycleValue = (TextView) this.findViewById(R.id.tv_duty_cycle_value);
// // 设置占空比调整监听器
// seekBarDutyCycle.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
// @Override
// public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// currentDutyCyclePercent = progress;
// tvDutyCycleValue.setText("占空比: " + progress + "%");
// }
//
// @Override
// public void onStartTrackingTouch(SeekBar seekBar) {}
//
// @Override
// public void onStopTrackingTouch(SeekBar seekBar) {}
// });
//
// // 设置正转按钮点击监听器
// btnRotateForward.setOnClickListener(v -> {
// if (motorController != null) {
// int dutyCycle = (int) (PWM_PERIOD * currentDutyCyclePercent / 100.0);
// motorController.rotateReverse(PWM_PERIOD, 0); // 确保反转PWM关闭
// motorController.rotateForward(PWM_PERIOD, dutyCycle);
// }
// });
//
// // 设置反转按钮点击监听器
// btnRotateReverse.setOnClickListener(v -> {
// if (motorController != null) {
// int dutyCycle = (int) (PWM_PERIOD * currentDutyCyclePercent / 100.0);
// motorController.rotateForward(PWM_PERIOD, 0); // 确保正转PWM关闭
// motorController.rotateReverse(PWM_PERIOD, dutyCycle);
// }
// });
// 初始化动画管理器 // 初始化动画管理器
animationManager = new RobotFaceAnimationManager(this, ivFace); animationManager = new RobotFaceAnimationManager(this, ivFace);
@ -155,22 +196,18 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
handler.post(faceAnimationRunnable); handler.post(faceAnimationRunnable);
}).start(); }).start();
// 检查并请求必要的权限 // 检查并请求必要的权限
checkAndRequestPermissions(); checkAndRequestPermissions();
// 隐藏状态栏和导航栏 // 隐藏状态栏和导航栏
hideSystemBars(); hideSystemBars();
// 初始化设备管理器 // 初始化设备管理器
initDeviceManager(); initDeviceManager();
//testMotorControl();
// // 延迟2秒后开始测试确保设备管理器初始化完成 testMotorControl();
// handler.postDelayed(new Runnable() {
// @Override
// public void run() {
// startProtocolTests();
// }
// }, 2000);
//xiaozhi //xiaozhi
initAudio(); initAudio();
@ -285,6 +322,16 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
} }
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(TAG, "keyCode: "+ keyCode);
if (keyCode == HEAD_TOUCH_KEY) {
// 处理返回键按下事件
Log.d(TAG, "触摸了机器人的头");
return true; // 返回true表示事件已被处理
}
return super.onKeyDown(keyCode, event); // 让系统继续处理其他按键事件
}
private void startProtocolTests() { private void startProtocolTests() {
LogManager.d(TAG, "开始协议测试..."); LogManager.d(TAG, "开始协议测试...");
@ -389,6 +436,18 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
gpioManager = null; gpioManager = null;
} }
// 中断电机控制线程
if (motorControlThread != null && motorControlThread.isAlive()) {
try {
motorControlThread.interrupt();
motorControlThread.join(1000); // 等待线程结束最多等待1秒
LogManager.d(TAG, "电机控制线程已中断");
} catch (InterruptedException e) {
LogManager.e(TAG, "等待电机控制线程结束时被中断");
}
motorControlThread = null;
}
// 释放电机控制器资源 // 释放电机控制器资源
if (motorController != null) { if (motorController != null) {
try { try {
@ -452,7 +511,17 @@ private void testMotorControl() {
return; return;
} }
new Thread(() -> { // 如果之前的线程还在运行先中断它
if (motorControlThread != null && motorControlThread.isAlive()) {
motorControlThread.interrupt();
try {
motorControlThread.join(1000); // 等待线程结束最多等待1秒
} catch (InterruptedException e) {
LogManager.e(TAG, "等待之前的电机控制线程结束时被中断");
}
}
motorControlThread = new Thread(() -> {
try { try {
// 打开电机 // 打开电机
LogManager.d(TAG, "打开电机"); LogManager.d(TAG, "打开电机");
@ -462,44 +531,52 @@ private void testMotorControl() {
} }
// 设置PWM参数 // 设置PWM参数
final int period = 1000000; final int period = 1000000;
final int dutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period final int fdutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period
final int rdutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period
Thread.sleep(10000); // Thread.sleep(2000);
// LogManager.d(TAG, "电机正转");
// motorController.rotateReverse(period, 0); // 确保反转PWM关闭 // motorController.rotateReverse(period, 0); // 确保反转PWM关闭
// if (!motorController.rotateForward(period, dutyCycle)) { // if (!motorController.rotateForward(period, dutyCycle)) {
// LogManager.e(TAG, "电机正转失败"); // LogManager.e(TAG, "电机正转失败");
// } // }
// Thread.sleep(2000);
// // 电机反转
// motorController.rotateForward(period, 0);
// if (!motorController.rotateReverse(period, dutyCycle)) {
// LogManager.e(TAG, "电机反转失败");
// }
// 循环20次正反转 // 循环20次正反转
for (int i = 0; i < 100; i++) { for (int i = 0; i < 10000; i++) {
LogManager.d(TAG, "开始第" + (i + 1) + "次正反转测试"); LogManager.d(TAG, "开始第" + (i + 1) + "次正反转测试");
// 电机正转 // 电机正转
LogManager.d(TAG, "电机正转"); LogManager.d(TAG, "电机正转");
motorController.rotateReverse(period, 0); // 确保反转PWM关闭 motorController.rotateReverse(period, 0); // 确保反转PWM关闭
if (!motorController.rotateForward(period, dutyCycle)) { if (!motorController.rotateForward(period, fdutyCycle)) {
LogManager.e(TAG, "电机正转失败"); LogManager.e(TAG, "电机正转失败");
break; break;
} }
// 等待100ms // 等待100ms
Thread.sleep(100); Thread.sleep(120);
// 停止正转 // 停止正转
motorController.rotateForward(period, 0); motorController.rotateForward(period, 0);
Thread.sleep(1000);
// 电机反转 // 电机反转
LogManager.d(TAG, "电机反转"); LogManager.d(TAG, "电机反转");
if (!motorController.rotateReverse(period, dutyCycle)) { if (!motorController.rotateReverse(period, rdutyCycle)) {
LogManager.e(TAG, "电机反转失败"); LogManager.e(TAG, "电机反转失败");
break; break;
} }
// 等待100ms // 等待100ms
Thread.sleep(100); Thread.sleep(40);
// 停止反转 // 停止反转
motorController.rotateReverse(period, 0); motorController.rotateReverse(period, 0);
Thread.sleep(1000);
} }
// 测试完成关闭电机 // 测试完成关闭电机
@ -513,7 +590,8 @@ private void testMotorControl() {
LogManager.e(TAG, "电机测试异常: " + e.getMessage()); LogManager.e(TAG, "电机测试异常: " + e.getMessage());
motorController.turnOffMotor(); motorController.turnOffMotor();
} }
}).start(); });
motorControlThread.start();
} }
@Override @Override

View File

@ -24,7 +24,7 @@ public class MotorController {
// PWM路径常量 // PWM路径常量
private static final String PWM_FORWARD_PATH = "/sys/class/pwm/pwmchip0/pwm0/"; private static final String PWM_FORWARD_PATH = "/sys/class/pwm/pwmchip0/pwm0/";
private static final String PWM_REVERSE_PATH = "/sys/class/pwm/pwmchip1/pwm0/"; private static final String PWM_REVERSE_PATH = "/sys/class/pwm/pwmchip2/pwm0/";
private static final String PWM_PERIOD_FILE = "period"; private static final String PWM_PERIOD_FILE = "period";
private static final String PWM_DUTY_CYCLE_FILE = "duty_cycle"; private static final String PWM_DUTY_CYCLE_FILE = "duty_cycle";
private static final String PWM_ENABLE_FILE = "enable"; private static final String PWM_ENABLE_FILE = "enable";

View File

@ -4,9 +4,72 @@
android:id="@+id/main_layout" android:id="@+id/main_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity"> tools:context=".MainActivity">
<com.ismart.ib86.view.RobotEyesView <com.ismart.ib86.view.RobotEyesView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<ImageView
android:id="@+id/iv_face"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="-150dp"
android:src="@drawable/anim_face_xunhuan"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:padding="16dp"
android:background="#80000000">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_rotate_forward"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="正转"
android:layout_marginEnd="8dp"/>
<Button
android:id="@+id/btn_rotate_reverse"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="反转"
android:layout_marginStart="8dp"/>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="占空比调整"
android:textColor="#FFFFFF"
android:layout_marginTop="8dp"/>
<SeekBar
android:id="@+id/seekbar_duty_cycle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="30"
android:layout_marginTop="4dp"/>
<TextView
android:id="@+id/tv_duty_cycle_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="占空比: 30%"
android:textColor="#FFFFFF"
android:layout_marginTop="4dp"/>
</LinearLayout>
</RelativeLayout> </RelativeLayout>