添加pwm控制,后期写到驱动去
This commit is contained in:
parent
9688ebaedf
commit
3e8cefab49
@ -30,6 +30,7 @@ import com.ismart.ib86.feature.serial.SerialPort.ASR5515DeviceManager;
|
|||||||
import com.ismart.ib86.feature.serial.SerialPort.ASR5515Protocol;
|
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.gpio.GpioTest;
|
||||||
|
import com.ismart.ib86.feature.motor.MotorController;
|
||||||
import com.ismart.ib86.view.RobotEyesView;
|
import com.ismart.ib86.view.RobotEyesView;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
@ -47,6 +48,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static final int BT_POWER_EN = 75;
|
private static final int BT_POWER_EN = 75;
|
||||||
private ASR5515DeviceManager deviceManager;
|
private ASR5515DeviceManager deviceManager;
|
||||||
|
private MotorController motorController;
|
||||||
// 使用弱引用避免内存泄漏
|
// 使用弱引用避免内存泄漏
|
||||||
private Runnable wearDetectionRunnable = new Runnable() {
|
private Runnable wearDetectionRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -80,18 +82,10 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
// 初始化UI控件
|
// 初始化UI控件
|
||||||
ivFace = (ImageView) this.findViewById(R.id.iv_face);
|
ivFace = (ImageView) this.findViewById(R.id.iv_face);
|
||||||
// btnPauseResume = findViewById(R.id.btn_pause_resume);
|
|
||||||
// btnSwitchFace = findViewById(R.id.btn_switch_face);
|
|
||||||
// seekBarSpeed = findViewById(R.id.seek_bar_speed);
|
|
||||||
// tvCurrentFace = findViewById(R.id.tv_current_face);
|
|
||||||
// tvSpeed = findViewById(R.id.tv_speed);
|
|
||||||
|
|
||||||
// 初始化动画管理器
|
// 初始化动画管理器
|
||||||
animationManager = new RobotFaceAnimationManager(this, ivFace);
|
animationManager = new RobotFaceAnimationManager(this, ivFace);
|
||||||
|
|
||||||
// 启动随机表情动画
|
|
||||||
playRandomFaceAnimation();
|
|
||||||
|
|
||||||
// 每5秒自动切换一次表情
|
// 每5秒自动切换一次表情
|
||||||
handler.postDelayed(new Runnable() {
|
handler.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -101,59 +95,6 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
// 设置暂停/继续按钮点击事件
|
|
||||||
// btnPauseResume.setOnClickListener(new View.OnClickListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onClick(View v) {
|
|
||||||
// boolean isPaused = animationManager.togglePause();
|
|
||||||
// btnPauseResume.setText(isPaused ? "继续" : "暂停");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 设置切换表情按钮点击事件
|
|
||||||
// btnSwitchFace.setOnClickListener(new View.OnClickListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onClick(View v) {
|
|
||||||
// String faceName = animationManager.switchToNextFace();
|
|
||||||
// tvCurrentFace.setText(faceName);
|
|
||||||
// Toast.makeText(MainActivity.this, "已切换到: " + faceName, Toast.LENGTH_SHORT).show();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 设置速度调节滑块变化事件
|
|
||||||
// seekBarSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
|
||||||
// @Override
|
|
||||||
// public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
|
||||||
// if (fromUser) {
|
|
||||||
// // 将进度值(0-100)转换为速度因子(0.5-2.0)
|
|
||||||
// float speedFactor = 0.5f + (progress / 100.0f) * 1.5f;
|
|
||||||
// animationManager.setSpeed(speedFactor);
|
|
||||||
// tvSpeed.setText(String.format("%.1fx", speedFactor));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
// // 不需要实现
|
|
||||||
// }
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
// // 不需要实现
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // 初始化速度显示
|
|
||||||
// tvSpeed.setText("1.0x");
|
|
||||||
|
|
||||||
// // 初始化表情名称显示
|
|
||||||
// tvCurrentFace.setText(animationManager.getCurrentFaceName());
|
|
||||||
|
|
||||||
// mainLayout = findViewById(R.id.main_layout);
|
|
||||||
// mainLayout.setBackgroundColor(Color.BLACK);
|
|
||||||
// robotEyesView = new RobotEyesView(this);
|
|
||||||
// mainLayout.addView(robotEyesView);
|
|
||||||
|
|
||||||
// 检查并请求必要的权限
|
// 检查并请求必要的权限
|
||||||
checkAndRequestPermissions();
|
checkAndRequestPermissions();
|
||||||
|
|
||||||
@ -161,14 +102,15 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
hideSystemBars();
|
hideSystemBars();
|
||||||
// 初始化设备管理器
|
// 初始化设备管理器
|
||||||
initDeviceManager();
|
initDeviceManager();
|
||||||
|
//testMotorControl();
|
||||||
|
|
||||||
// 延迟2秒后开始测试,确保设备管理器初始化完成
|
// 延迟2秒后开始测试,确保设备管理器初始化完成
|
||||||
// handler.postDelayed(new Runnable() {
|
handler.postDelayed(new Runnable() {
|
||||||
// @Override
|
@Override
|
||||||
// public void run() {
|
public void run() {
|
||||||
// startProtocolTests();
|
startProtocolTests();
|
||||||
// }
|
}
|
||||||
// }, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initDeviceManager() {
|
private void initDeviceManager() {
|
||||||
@ -178,6 +120,11 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
gpioManager.setDirection(BT_POWER_EN, GpioManager.DIRECTION_OUT);
|
gpioManager.setDirection(BT_POWER_EN, GpioManager.DIRECTION_OUT);
|
||||||
gpioManager.setValue(BT_POWER_EN, GpioManager.VALUE_HIGH);
|
gpioManager.setValue(BT_POWER_EN, GpioManager.VALUE_HIGH);
|
||||||
|
|
||||||
|
// 初始化电机控制器
|
||||||
|
motorController = MotorController.getInstance();
|
||||||
|
motorController.init();
|
||||||
|
LogManager.d(TAG, "电机控制器初始化完成");
|
||||||
|
|
||||||
deviceManager = new ASR5515DeviceManager(this, DEVICE_PATH, BAUD_RATE);
|
deviceManager = new ASR5515DeviceManager(this, DEVICE_PATH, BAUD_RATE);
|
||||||
// 设置设备检查回调
|
// 设置设备检查回调
|
||||||
deviceManager.setDeviceCheckListener(deviceInfo -> {
|
deviceManager.setDeviceCheckListener(deviceInfo -> {
|
||||||
@ -315,12 +262,12 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
// deviceManager.queryBtVersion();
|
// deviceManager.queryBtVersion();
|
||||||
// }
|
// }
|
||||||
// }, 2000);
|
// }, 2000);
|
||||||
// deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
||||||
// deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
deviceManager.stopGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
||||||
// handler.postDelayed(new Runnable() {
|
// handler.postDelayed(new Runnable() {
|
||||||
// @Override
|
// @Override
|
||||||
// public void run() {
|
// public void run() {
|
||||||
// deviceManager.startGH3220Measure(ASR5515Protocol.GH3220MeasureType.SPO2);
|
// deviceManager.startGH3220Measure(ASR5515Protocol.GH3220MeasureType.HR);
|
||||||
// }
|
// }
|
||||||
// }, 1000);
|
// }, 1000);
|
||||||
|
|
||||||
@ -363,6 +310,16 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
gpioManager = null;
|
gpioManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放电机控制器资源
|
||||||
|
if (motorController != null) {
|
||||||
|
try {
|
||||||
|
motorController.release();
|
||||||
|
LogManager.d(TAG, "电机控制器资源已释放");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "释放电机控制器资源失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogManager.e(TAG, "资源释放过程中发生错误: " + e.getMessage());
|
LogManager.e(TAG, "资源释放过程中发生错误: " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -375,26 +332,15 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
* 随机播放一个表情动画
|
* 随机播放一个表情动画
|
||||||
*/
|
*/
|
||||||
private void playRandomFaceAnimation() {
|
private void playRandomFaceAnimation() {
|
||||||
// 可用的表情动画类型数组
|
|
||||||
int[] faceAnimations = {
|
|
||||||
RobotFaceAnimationManager.FACE_LOOP_0,
|
|
||||||
RobotFaceAnimationManager.FACE_LOOP_1,
|
|
||||||
RobotFaceAnimationManager.FACE_LOOP_2,
|
|
||||||
RobotFaceAnimationManager.FACE_LOOP_3,
|
|
||||||
RobotFaceAnimationManager.FACE_LOOP_4,
|
|
||||||
RobotFaceAnimationManager.FACE_HAPPY,
|
|
||||||
RobotFaceAnimationManager.FACE_SAD
|
|
||||||
};
|
|
||||||
|
|
||||||
// 随机选择一个表情
|
// 随机选择一个表情
|
||||||
int randomIndex = (int)(Math.random() * faceAnimations.length);
|
int selectedAnimation = (int)(Math.random() * 5);
|
||||||
int selectedAnimation = faceAnimations[randomIndex];
|
|
||||||
|
|
||||||
LogManager.d(TAG, "随机选择表情动画: " + selectedAnimation);
|
LogManager.d(TAG, "随机选择表情动画: " + selectedAnimation);
|
||||||
|
|
||||||
// 加载选中的动画
|
// 加载选中的动画
|
||||||
if (animationManager != null) {
|
if (animationManager != null) {
|
||||||
animationManager.loadFaceAnimation(selectedAnimation);
|
animationManager.loadFaceAnimation(selectedAnimation);
|
||||||
|
animationManager.setSpeed(0.4f);
|
||||||
} else {
|
} else {
|
||||||
LogManager.e(TAG, "动画管理器未初始化");
|
LogManager.e(TAG, "动画管理器未初始化");
|
||||||
}
|
}
|
||||||
@ -419,18 +365,91 @@ private void hideSystemBars() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
* 测试电机控制功能
|
||||||
|
*/
|
||||||
|
private void testMotorControl() {
|
||||||
|
if (motorController == null) {
|
||||||
|
LogManager.e(TAG, "电机控制器未初始化");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
// 打开电机
|
||||||
|
LogManager.d(TAG, "打开电机");
|
||||||
|
if (!motorController.turnOnMotor()) {
|
||||||
|
LogManager.e(TAG, "打开电机失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 设置PWM参数
|
||||||
|
final int period = 1000000;
|
||||||
|
final int dutyCycle = 1000000; // 使用90%的占空比,避免duty_cycle等于period
|
||||||
|
|
||||||
|
Thread.sleep(10000);
|
||||||
|
// LogManager.d(TAG, "电机正转");
|
||||||
|
// motorController.rotateReverse(period, 0); // 确保反转PWM关闭
|
||||||
|
// if (!motorController.rotateForward(period, dutyCycle)) {
|
||||||
|
// LogManager.e(TAG, "电机正转失败");
|
||||||
|
// }
|
||||||
|
// 循环20次正反转
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
LogManager.d(TAG, "开始第" + (i + 1) + "次正反转测试");
|
||||||
|
|
||||||
|
// 电机正转
|
||||||
|
LogManager.d(TAG, "电机正转");
|
||||||
|
motorController.rotateReverse(period, 0); // 确保反转PWM关闭
|
||||||
|
if (!motorController.rotateForward(period, dutyCycle)) {
|
||||||
|
LogManager.e(TAG, "电机正转失败");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待100ms
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
// 停止正转
|
||||||
|
motorController.rotateForward(period, 0);
|
||||||
|
|
||||||
|
// 电机反转
|
||||||
|
LogManager.d(TAG, "电机反转");
|
||||||
|
if (!motorController.rotateReverse(period, dutyCycle)) {
|
||||||
|
LogManager.e(TAG, "电机反转失败");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待100ms
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
|
// 停止反转
|
||||||
|
motorController.rotateReverse(period, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试完成,关闭电机
|
||||||
|
LogManager.d(TAG, "电机测试完成,关闭电机");
|
||||||
|
motorController.turnOffMotor();
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LogManager.e(TAG, "电机测试被中断: " + e.getMessage());
|
||||||
|
motorController.turnOffMotor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "电机测试异常: " + e.getMessage());
|
||||||
|
motorController.turnOffMotor();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWindowFocusChanged(boolean hasFocus) {
|
||||||
super.onWindowFocusChanged(hasFocus);
|
super.onWindowFocusChanged(hasFocus);
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
hideSystemBars();
|
hideSystemBars();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查并请求必要的权限
|
* 检查并请求必要的权限
|
||||||
*/
|
*/
|
||||||
private void checkAndRequestPermissions() {
|
private void checkAndRequestPermissions() {
|
||||||
// 检查是否已经有所需的权限
|
// 检查是否已经有所需的权限
|
||||||
boolean allPermissionsGranted = true;
|
boolean allPermissionsGranted = true;
|
||||||
for (String permission : REQUIRED_PERMISSIONS) {
|
for (String permission : REQUIRED_PERMISSIONS) {
|
||||||
@ -446,11 +465,11 @@ private void checkAndRequestPermissions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理权限请求结果
|
* 处理权限请求结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE) {
|
if (requestCode == PERMISSION_REQUEST_CODE) {
|
||||||
@ -472,6 +491,6 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
|
|||||||
LogManager.e(TAG, "部分权限被拒绝,可能影响应用功能");
|
LogManager.e(TAG, "部分权限被拒绝,可能影响应用功能");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -17,13 +17,13 @@ import androidx.core.content.ContextCompat;
|
|||||||
public class RobotFaceAnimationManager {
|
public class RobotFaceAnimationManager {
|
||||||
// 动画类型常量
|
// 动画类型常量
|
||||||
|
|
||||||
public static final int FACE_LOOP_0 = 1; // 循环表情0
|
public static final int FACE_LOOP_0 = 0; // 循环表情0
|
||||||
public static final int FACE_LOOP_1 = 2; // 循环表情1
|
public static final int FACE_LOOP_1 = 1; // 循环表情1
|
||||||
public static final int FACE_LOOP_2 = 3; // 循环表情2
|
public static final int FACE_LOOP_2 = 2; // 循环表情2
|
||||||
public static final int FACE_LOOP_3 = 4; // 循环表情3
|
public static final int FACE_LOOP_3 = 3; // 循环表情3
|
||||||
public static final int FACE_LOOP_4 = 5; // 循环表情4
|
public static final int FACE_LOOP_4 = 4; // 循环表情4
|
||||||
public static final int FACE_HAPPY = 6; // 开心表情
|
public static final int FACE_HAPPY = 5; // 开心表情
|
||||||
public static final int FACE_SAD = 7; // 悲伤表情
|
public static final int FACE_SAD = 6; // 悲伤表情
|
||||||
|
|
||||||
// 动画资源ID数组
|
// 动画资源ID数组
|
||||||
private static final int[] FACE_ANIMATIONS = {
|
private static final int[] FACE_ANIMATIONS = {
|
||||||
@ -98,9 +98,9 @@ public class RobotFaceAnimationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 应用速度设置
|
// 应用速度设置
|
||||||
if (speedFactor != 1.0f) {
|
// if (speedFactor != 1.0f) {
|
||||||
applySpeed(speedFactor);
|
// applySpeed(speedFactor);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 设置动画到ImageView
|
// 设置动画到ImageView
|
||||||
imageView.setImageDrawable(currentAnimation);
|
imageView.setImageDrawable(currentAnimation);
|
||||||
|
@ -0,0 +1,249 @@
|
|||||||
|
package com.ismart.ib86.feature.motor;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.ismart.ib86.common.utils.LogManager;
|
||||||
|
import com.ismart.ib86.feature.gpio.GpioManager;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电机控制器类,用于控制机器人抬头点头的电机
|
||||||
|
* 采用单例模式确保全局只有一个控制实例
|
||||||
|
*/
|
||||||
|
public class MotorController {
|
||||||
|
private static final String TAG = "MotorController";
|
||||||
|
private static volatile MotorController instance;
|
||||||
|
|
||||||
|
// GPIO控制常量
|
||||||
|
private static final int MOTOR_CONTROL_GPIO = 59; // 电机开关GPIO
|
||||||
|
private static final int MOTOR_SLEEP_GPIO = 65;
|
||||||
|
private static final int GPIO_HIGH = 1; // GPIO高电平
|
||||||
|
private static final int GPIO_LOW = 0; // GPIO低电平
|
||||||
|
|
||||||
|
// 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_PERIOD_FILE = "period";
|
||||||
|
private static final String PWM_DUTY_CYCLE_FILE = "duty_cycle";
|
||||||
|
private static final String PWM_ENABLE_FILE = "enable";
|
||||||
|
|
||||||
|
// 电机状态枚举
|
||||||
|
public enum MotorState {
|
||||||
|
STOPPED, // 停止状态
|
||||||
|
FORWARD, // 正转状态
|
||||||
|
REVERSE // 反转状态
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前电机状态
|
||||||
|
private MotorState currentState = MotorState.STOPPED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取MotorController单例实例
|
||||||
|
* @return MotorController实例
|
||||||
|
*/
|
||||||
|
public static MotorController getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (MotorController.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new MotorController();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有构造函数,防止外部实例化
|
||||||
|
*/
|
||||||
|
private MotorController() {
|
||||||
|
// 私有构造函数
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化电机控制器
|
||||||
|
* @return 是否初始化成功
|
||||||
|
*/
|
||||||
|
public boolean init() {
|
||||||
|
try {
|
||||||
|
// 初始化GPIO
|
||||||
|
GpioManager.getInstance().setDirection(MOTOR_CONTROL_GPIO, GpioManager.DIRECTION_OUT);
|
||||||
|
// 默认关闭电机
|
||||||
|
return turnOffMotor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to initialize motor controller", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开电机
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean turnOnMotor() {
|
||||||
|
try {
|
||||||
|
rotateForward(1000000, 0); // 确保正转PWM关闭
|
||||||
|
enablePwm(PWM_FORWARD_PATH, false);
|
||||||
|
enablePwm(PWM_FORWARD_PATH, true);
|
||||||
|
rotateReverse(1000000, 0); // 确保反转PWM关闭
|
||||||
|
enablePwm(PWM_REVERSE_PATH, true);
|
||||||
|
boolean state = GpioManager.getInstance().setValue(MOTOR_CONTROL_GPIO, GPIO_HIGH);
|
||||||
|
// 设置SLEEP
|
||||||
|
GpioManager.getInstance().setDirection(MOTOR_SLEEP_GPIO, GpioManager.DIRECTION_OUT);
|
||||||
|
GpioManager.getInstance().setValue(MOTOR_SLEEP_GPIO, GpioManager.VALUE_HIGH);
|
||||||
|
return state;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to turn on motor", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭电机
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean turnOffMotor() {
|
||||||
|
try {
|
||||||
|
// 根据当前状态将相应PWM通道的参数设为0
|
||||||
|
String pwmPath;
|
||||||
|
switch (currentState) {
|
||||||
|
case FORWARD:
|
||||||
|
pwmPath = PWM_FORWARD_PATH;
|
||||||
|
break;
|
||||||
|
case REVERSE:
|
||||||
|
pwmPath = PWM_REVERSE_PATH;
|
||||||
|
break;
|
||||||
|
case STOPPED:
|
||||||
|
default:
|
||||||
|
// 如果已经是停止状态,直接关闭GPIO
|
||||||
|
return GpioManager.getInstance().setValue(MOTOR_CONTROL_GPIO, GPIO_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将period和dutyCycle设为0
|
||||||
|
setPwmParameters(pwmPath, 1000000, 0);
|
||||||
|
|
||||||
|
// 关闭电机控制GPIO
|
||||||
|
boolean result = GpioManager.getInstance().setValue(MOTOR_CONTROL_GPIO, GPIO_LOW);
|
||||||
|
|
||||||
|
// 更新状态为停止
|
||||||
|
currentState = MotorState.STOPPED;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to turn off motor", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制电机正转
|
||||||
|
* @param period PWM周期(纳秒)
|
||||||
|
* @param dutyCycle PWM占空比(纳秒)
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean rotateForward(int period, int dutyCycle) {
|
||||||
|
if (setPwmParameters(PWM_FORWARD_PATH, period, dutyCycle)) {
|
||||||
|
currentState = MotorState.FORWARD;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制电机反转
|
||||||
|
* @param period PWM周期(纳秒)
|
||||||
|
* @param dutyCycle PWM占空比(纳秒)
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean rotateReverse(int period, int dutyCycle) {
|
||||||
|
if (setPwmParameters(PWM_REVERSE_PATH, period, dutyCycle)) {
|
||||||
|
currentState = MotorState.REVERSE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置PWM参数
|
||||||
|
* @param basePath PWM基础路径
|
||||||
|
* @param period 周期
|
||||||
|
* @param dutyCycle 占空比
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
private boolean setPwmParameters(String basePath, int period, int dutyCycle) {
|
||||||
|
try {
|
||||||
|
//enablePwm(basePath, false);
|
||||||
|
writeToFile(basePath + PWM_PERIOD_FILE, String.valueOf(period));
|
||||||
|
writeToFile(basePath + PWM_DUTY_CYCLE_FILE, String.valueOf(dutyCycle));
|
||||||
|
// 使能PWM
|
||||||
|
//enablePwm(basePath, true);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to set PWM parameters", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入文件
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param content 内容
|
||||||
|
* @throws IOException IO异常
|
||||||
|
*/
|
||||||
|
private void writeToFile(String filePath, String content) throws IOException {
|
||||||
|
FileWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new FileWriter(filePath);
|
||||||
|
writer.write(content);
|
||||||
|
} finally {
|
||||||
|
if (writer != null) {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to close file writer", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制PWM使能状态
|
||||||
|
* @param basePath PWM基础路径
|
||||||
|
* @param enable true表示使能,false表示禁用
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean enablePwm(String basePath, boolean enable) {
|
||||||
|
try {
|
||||||
|
writeToFile(basePath + PWM_ENABLE_FILE, enable ? "1" : "0");
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Failed to " + (enable ? "enable" : "disable") + " PWM", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制电机旋转到指定角度(预留API,暂不实现)
|
||||||
|
* @param angle 目标角度(度)
|
||||||
|
* @param speed 旋转速度(可选参数)
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean rotateToAngle(float angle, float speed) {
|
||||||
|
// TODO: 实现角度控制功能
|
||||||
|
Log.i(TAG, "rotateToAngle API called, but not implemented yet");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放资源
|
||||||
|
*/
|
||||||
|
public void release() {
|
||||||
|
try {
|
||||||
|
// 关闭电机
|
||||||
|
turnOffMotor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to release resources", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -199,7 +199,6 @@ public class ASR5515Protocol {
|
|||||||
public static final short CMD_HOST_STATUS = 0x0079; // 主机状态同步请求
|
public static final short CMD_HOST_STATUS = 0x0079; // 主机状态同步请求
|
||||||
public static final short CMD_HOST_STATUS_RESP = 0x007A; // 主机状态同步响应
|
public static final short CMD_HOST_STATUS_RESP = 0x007A; // 主机状态同步响应
|
||||||
public static final short CMD_HOST_STATUS_BOOT_RESP = 0x007C; //主机状态,启动状态
|
public static final short CMD_HOST_STATUS_BOOT_RESP = 0x007C; //主机状态,启动状态
|
||||||
// 新增命令
|
|
||||||
public static final short CMD_BOOT_BIN_CHECK = 0x007D; // boot bin检查请求 [125 0 0]
|
public static final short CMD_BOOT_BIN_CHECK = 0x007D; // boot bin检查请求 [125 0 0]
|
||||||
public static final short CMD_BOOT_BIN_CHECK_RESP = 0x007E; // boot bin检查响应 [126 sn len 0/1]
|
public static final short CMD_BOOT_BIN_CHECK_RESP = 0x007E; // boot bin检查响应 [126 sn len 0/1]
|
||||||
public static final short CMD_COLLECT_FREQ_SET = 0x00C9; // 采集频率设置 [201 0 len 32]
|
public static final short CMD_COLLECT_FREQ_SET = 0x00C9; // 采集频率设置 [201 0 len 32]
|
||||||
@ -240,7 +239,7 @@ public class ASR5515Protocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] createFrame(short command, byte[] data) {
|
public static byte[] createFrame(short command, byte[] data) {
|
||||||
LogManager.d(TAG, "LEN :" + data.length);
|
//LogManager.d(TAG, "LEN :" + data.length);
|
||||||
int frameLength = 1 + 2 + 2 + 2 + data.length + 1; // start + command(2bytes) + sn(2bytes) + len(2bytes) + data + end
|
int frameLength = 1 + 2 + 2 + 2 + data.length + 1; // start + command(2bytes) + sn(2bytes) + len(2bytes) + data + end
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(frameLength);
|
ByteBuffer buffer = ByteBuffer.allocate(frameLength);
|
||||||
|
|
||||||
@ -319,7 +318,7 @@ public class ASR5515Protocol {
|
|||||||
System.arraycopy(data, startIndex + totalFrameLength, frame.remainingData, 0, frame.remainingData.length);
|
System.arraycopy(data, startIndex + totalFrameLength, frame.remainingData, 0, frame.remainingData.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.d(TAG, "Frame parsed - type: " + type + ", len: " + len + ", data length: " + frameData.length);
|
//LogManager.d(TAG, "Frame parsed - type: " + type + ", len: " + len + ", data length: " + frameData.length);
|
||||||
return frame;
|
return frame;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogManager.e(TAG, "Parse frame error: " + e.getMessage());
|
LogManager.e(TAG, "Parse frame error: " + e.getMessage());
|
||||||
|
@ -11,152 +11,14 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center">
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="-150dp">
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_face"
|
android:id="@+id/iv_face"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/anim_face_xunhuan"/>
|
android:src="@drawable/anim_face_xunhuan"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- <LinearLayout
|
|
||||||
android:id="@+id/control_panel"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:background="#33000000"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:layout_marginTop="16dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginBottom="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="当前表情:"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="14sp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_current_face"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="普通表情"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginRight="16dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="速度:"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="14sp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tv_speed"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="1.0x"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="14sp"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_marginBottom="8dp">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_pause_resume"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="暂停"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:backgroundTint="#444444"
|
|
||||||
android:layout_marginRight="8dp"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/btn_switch_face"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="切换表情"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:backgroundTint="#444444"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="速度调节"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:layout_marginBottom="4dp"/>
|
|
||||||
|
|
||||||
<SeekBar
|
|
||||||
android:id="@+id/seek_bar_speed"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:max="100"
|
|
||||||
android:progress="50"
|
|
||||||
android:progressTint="#FFFFFF"
|
|
||||||
android:thumbTint="#FFFFFF"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_marginTop="4dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="慢"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="12sp"/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="正常"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="12sp"/>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_weight="1"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="快"
|
|
||||||
android:textColor="#FFFFFF"
|
|
||||||
android:textSize="12sp"/>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
</LinearLayout> -->
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user