修改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;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
@ -13,7 +11,7 @@ import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
@ -22,7 +20,6 @@ import android.view.View;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@ -32,14 +29,10 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
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.serial.SerialPort.ASR5515DeviceManager;
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
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.view.RobotEyesView;
import com.lhht.xiaozhi.models.websokcet.send.WebSocketSendMsgFactory;
import com.lhht.xiaozhi.settings.SettingsManager;
import com.lhht.xiaozhi.utils.DeviceUtils;
@ -52,9 +45,11 @@ import java.util.concurrent.Executors;
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 DEVICE_PATH = "/dev/ttyS3";
private static final int HEAD_TOUCH_KEY = 285;
private static final int BAUD_RATE = 921600;
// 权限请求码
@ -95,6 +90,7 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
private short[] decodedBuffer;
private short[] recordBuffer;
private byte[] encodedBuffer;
private boolean hasStartedCall = false;
private boolean isRecording = false;
private volatile boolean isDestroyed = false;
@ -102,17 +98,25 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
private boolean isPlaying = false;
private String sessionId = ""; // 添加session_id字段
private long lastAudioDataTime = 0; // 新增记录最后一次收到音频数据的时间
private Thread motorControlThread; // 用于跟踪电机控制线程
private boolean isCheckingPlaybackStatus = false;
//xiaozhi end
// HeadTouchManager removed
// UI控件
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 boolean isCalibrating = false;
private boolean isForwardCalibration = false;
private boolean isReverseCalibration = false;
private Runnable wearDetectionRunnable = new Runnable() {
@Override
@ -131,6 +135,43 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
// 初始化UI控件
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);
@ -155,22 +196,18 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
handler.post(faceAnimationRunnable);
}).start();
// 检查并请求必要的权限
checkAndRequestPermissions();
// 隐藏状态栏和导航栏
hideSystemBars();
// 初始化设备管理器
initDeviceManager();
//testMotorControl();
// // 延迟2秒后开始测试确保设备管理器初始化完成
// handler.postDelayed(new Runnable() {
// @Override
// public void run() {
// startProtocolTests();
// }
// }, 2000);
testMotorControl();
//xiaozhi
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() {
LogManager.d(TAG, "开始协议测试...");
@ -389,6 +436,18 @@ public class MainActivity extends AppCompatActivity implements WebSocketManager.
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) {
try {
@ -452,7 +511,17 @@ private void testMotorControl() {
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 {
// 打开电机
LogManager.d(TAG, "打开电机");
@ -462,44 +531,52 @@ private void testMotorControl() {
}
// 设置PWM参数
final int period = 1000000;
final int dutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period
Thread.sleep(10000);
// LogManager.d(TAG, "电机正转");
final int fdutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period
final int rdutyCycle = 1000000; // 使用90%的占空比避免duty_cycle等于period
// Thread.sleep(2000);
// motorController.rotateReverse(period, 0); // 确保反转PWM关闭
// if (!motorController.rotateForward(period, dutyCycle)) {
// LogManager.e(TAG, "电机正转失败");
// }
// Thread.sleep(2000);
// // 电机反转
// motorController.rotateForward(period, 0);
// if (!motorController.rotateReverse(period, dutyCycle)) {
// LogManager.e(TAG, "电机反转失败");
// }
// 循环20次正反转
for (int i = 0; i < 100; i++) {
for (int i = 0; i < 10000; i++) {
LogManager.d(TAG, "开始第" + (i + 1) + "次正反转测试");
// 电机正转
LogManager.d(TAG, "电机正转");
motorController.rotateReverse(period, 0); // 确保反转PWM关闭
if (!motorController.rotateForward(period, dutyCycle)) {
if (!motorController.rotateForward(period, fdutyCycle)) {
LogManager.e(TAG, "电机正转失败");
break;
}
// 等待100ms
Thread.sleep(100);
Thread.sleep(120);
// 停止正转
motorController.rotateForward(period, 0);
Thread.sleep(1000);
// 电机反转
LogManager.d(TAG, "电机反转");
if (!motorController.rotateReverse(period, dutyCycle)) {
if (!motorController.rotateReverse(period, rdutyCycle)) {
LogManager.e(TAG, "电机反转失败");
break;
}
// 等待100ms
Thread.sleep(100);
Thread.sleep(40);
// 停止反转
motorController.rotateReverse(period, 0);
Thread.sleep(1000);
}
// 测试完成关闭电机
@ -513,7 +590,8 @@ private void testMotorControl() {
LogManager.e(TAG, "电机测试异常: " + e.getMessage());
motorController.turnOffMotor();
}
}).start();
});
motorControlThread.start();
}
@Override

View File

@ -24,7 +24,7 @@ public class MotorController {
// PWM路径常量
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_DUTY_CYCLE_FILE = "duty_cycle";
private static final String PWM_ENABLE_FILE = "enable";

View File

@ -4,9 +4,72 @@
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity">
<com.ismart.ib86.view.RobotEyesView
android:layout_width="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>