641 lines
16 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package hands
import (
"bytes"
"encoding/json"
"fmt"
"hands/config"
"hands/define"
"log"
"math/rand/v2"
"net/http"
"strings"
"sync"
"time"
)
// 传感器数据结构体
type SensorData struct {
Interface string `json:"interface"`
Thumb int `json:"thumb"`
Index int `json:"index"`
Middle int `json:"middle"`
Ring int `json:"ring"`
Pinky int `json:"pinky"`
PalmPosition []byte `json:"palmPosition"`
LastUpdate time.Time `json:"lastUpdate"`
}
// 手型配置结构体
type HandConfig struct {
HandType string `json:"handType"`
HandId uint32 `json:"handId"`
}
var (
HandConfigMutex sync.RWMutex
HandConfigs map[string]*HandConfig // 每个接口的手型配置
SensorDataMap map[string]*SensorData // 每个接口的传感器数据
SensorMutex sync.RWMutex
AnimationActive map[string]bool // 每个接口的动画状态
AnimationMutex sync.Mutex
StopAnimationMap map[string]chan struct{} // 每个接口的停止动画通道
)
func InitHands() {
// 初始化传感器数据映射
SensorDataMap = make(map[string]*SensorData)
for _, ifName := range config.Config.AvailableInterfaces {
SensorDataMap[ifName] = &SensorData{
Interface: ifName,
Thumb: 0,
Index: 0,
Middle: 0,
Ring: 0,
Pinky: 0,
PalmPosition: []byte{128, 128, 128, 128},
LastUpdate: time.Now(),
}
}
// 初始化动画状态映射
AnimationActive = make(map[string]bool)
StopAnimationMap = make(map[string]chan struct{})
for _, ifName := range config.Config.AvailableInterfaces {
AnimationActive[ifName] = false
StopAnimationMap[ifName] = make(chan struct{}, 1)
}
HandConfigs = make(map[string]*HandConfig)
}
func SetHandConfig(ifName, handType string, handId uint32) {
HandConfigMutex.Lock()
defer HandConfigMutex.Unlock()
HandConfigs[ifName] = &HandConfig{
HandType: handType,
HandId: handId,
}
log.Printf("🔧 接口 %s 手型配置已更新: %s (0x%X)", ifName, handType, handId)
}
func GetHandConfig(ifName string) *HandConfig {
HandConfigMutex.RLock()
if handConfig, exists := HandConfigs[ifName]; exists {
HandConfigMutex.RUnlock()
return handConfig
}
HandConfigMutex.RUnlock()
// 创建默认配置
HandConfigMutex.Lock()
defer HandConfigMutex.Unlock()
// 再次检查(双重检查锁定)
if handConfig, exists := HandConfigs[ifName]; exists {
return handConfig
}
// 创建默认配置(右手)
HandConfigs[ifName] = &HandConfig{
HandType: "right",
HandId: define.HAND_TYPE_RIGHT,
}
log.Printf("🆕 为接口 %s 创建默认手型配置: 右手 (0x%X)", ifName, define.HAND_TYPE_RIGHT)
return HandConfigs[ifName]
}
// 解析手型参数
func ParseHandType(handType string, handId uint32, ifName string) uint32 {
// 如果提供了有效的 handId直接使用
if handId != 0 {
return handId
}
// 根据 handType 字符串确定 ID
switch strings.ToLower(handType) {
case "left":
return define.HAND_TYPE_LEFT
case "right":
return define.HAND_TYPE_RIGHT
default:
// 使用接口的配置
handConfig := GetHandConfig(ifName)
return handConfig.HandId
}
}
// 验证接口是否可用
func IsValidInterface(ifName string) bool {
for _, validIface := range config.Config.AvailableInterfaces {
if ifName == validIface {
return true
}
}
return false
}
type CanMessage struct {
Interface string `json:"interface"`
ID uint32 `json:"id"`
Data []byte `json:"data"`
}
// 发送手指姿态指令 - 支持手型参数
func SendFingerPose(ifName string, pose []byte, handType string, handId uint32) error {
if len(pose) != 6 {
return fmt.Errorf("无效的姿态数据长度,需要 6 个字节")
}
// 如果未指定接口,使用默认接口
if ifName == "" {
ifName = config.Config.DefaultInterface
}
// 验证接口
if !IsValidInterface(ifName) {
return fmt.Errorf("无效的接口 %s可用接口: %v", ifName, config.Config.AvailableInterfaces)
}
// 解析手型 ID
canId := ParseHandType(handType, handId, ifName)
// 添加随机扰动
perturbedPose := make([]byte, len(pose))
for i, v := range pose {
perturbedPose[i] = perturb(v, 5)
}
// 构造 CAN 消息
msg := CanMessage{
Interface: ifName,
ID: canId, // 使用动态的手型 ID
Data: append([]byte{0x01}, perturbedPose...),
}
err := sendToCanService(msg)
if err == nil {
handTypeName := "右手"
if canId == define.HAND_TYPE_LEFT {
handTypeName = "左手"
}
log.Printf("✅ %s (%s, 0x%X) 手指动作已发送: [%X %X %X %X %X %X]",
ifName, handTypeName, canId, perturbedPose[0], perturbedPose[1], perturbedPose[2],
perturbedPose[3], perturbedPose[4], perturbedPose[5])
} else {
log.Printf("❌ %s 手指控制发送失败: %v", ifName, err)
}
return err
}
// 在 base 基础上进行 ±delta 的扰动,范围限制在 [0, 255]
func perturb(base byte, delta int) byte {
offset := rand.IntN(2*delta+1) - delta
v := int(base) + offset
if v < 0 {
v = 0
}
if v > 255 {
v = 255
}
return byte(v)
}
// 发送请求到 CAN 服务
func sendToCanService(msg CanMessage) error {
jsonData, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("JSON 编码错误: %v", err)
}
resp, err := http.Post(config.Config.CanServiceURL+"/api/can", "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return fmt.Errorf("CAN 服务请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var errResp define.ApiResponse
if err := json.NewDecoder(resp.Body).Decode(&errResp); err != nil {
return fmt.Errorf("CAN 服务返回错误HTTP %d", resp.StatusCode)
}
return fmt.Errorf("CAN 服务返回错误: %s", errResp.Error)
}
return nil
}
// 发送掌部姿态指令 - 支持手型参数
func SendPalmPose(ifName string, pose []byte, handType string, handId uint32) error {
if len(pose) != 4 {
return fmt.Errorf("无效的姿态数据长度,需要 4 个字节")
}
// 如果未指定接口,使用默认接口
if ifName == "" {
ifName = config.Config.DefaultInterface
}
// 验证接口
if !IsValidInterface(ifName) {
return fmt.Errorf("无效的接口 %s可用接口: %v", ifName, config.Config.AvailableInterfaces)
}
// 解析手型 ID
canId := ParseHandType(handType, handId, ifName)
// 添加随机扰动
perturbedPose := make([]byte, len(pose))
for i, v := range pose {
perturbedPose[i] = perturb(v, 8)
}
// 构造 CAN 消息
msg := CanMessage{
Interface: ifName,
ID: canId, // 使用动态的手型 ID
Data: append([]byte{0x04}, perturbedPose...),
}
err := sendToCanService(msg)
if err == nil {
handTypeName := "右手"
if canId == define.HAND_TYPE_LEFT {
handTypeName = "左手"
}
log.Printf("✅ %s (%s, 0x%X) 掌部姿态已发送: [%X %X %X %X]",
ifName, handTypeName, canId, perturbedPose[0], perturbedPose[1], perturbedPose[2], perturbedPose[3])
// 更新传感器数据中的掌部位置
SensorMutex.Lock()
if sensorData, exists := SensorDataMap[ifName]; exists {
copy(sensorData.PalmPosition, perturbedPose)
sensorData.LastUpdate = time.Now()
}
SensorMutex.Unlock()
} else {
log.Printf("❌ %s 掌部控制发送失败: %v", ifName, err)
}
return err
}
// 执行波浪动画 - 支持手型参数
func StartWaveAnimation(ifName string, speed int, handType string, handId uint32) {
if speed <= 0 {
speed = 500 // 默认速度
}
// 如果未指定接口,使用默认接口
if ifName == "" {
ifName = config.Config.DefaultInterface
}
// 验证接口
if !IsValidInterface(ifName) {
log.Printf("❌ 无法启动波浪动画: 无效的接口 %s", ifName)
return
}
AnimationMutex.Lock()
// 如果已经有动画在运行,先停止它
if AnimationActive[ifName] {
select {
case StopAnimationMap[ifName] <- struct{}{}:
// 发送成功
default:
// 通道已满,无需发送
}
StopAnimationMap[ifName] = make(chan struct{}, 1)
}
AnimationActive[ifName] = true
AnimationMutex.Unlock()
currentStopChannel := StopAnimationMap[ifName]
go func() {
defer func() {
AnimationMutex.Lock()
AnimationActive[ifName] = false
AnimationMutex.Unlock()
log.Printf("👋 %s 波浪动画已完成", ifName)
}()
fingerOrder := []int{0, 1, 2, 3, 4, 5}
open := byte(64) // 0x40
close := byte(192) // 0xC0
log.Printf("🚀 开始 %s 波浪动画", ifName)
// 动画循环
for {
select {
case <-currentStopChannel:
log.Printf("🛑 %s 波浪动画被用户停止", ifName)
return
default:
// 波浪张开
for _, idx := range fingerOrder {
pose := make([]byte, 6)
for j := 0; j < 6; j++ {
if j == idx {
pose[j] = open
} else {
pose[j] = close
}
}
if err := SendFingerPose(ifName, pose, handType, handId); err != nil {
log.Printf("%s 动画发送失败: %v", ifName, err)
return
}
delay := time.Duration(speed) * time.Millisecond
select {
case <-currentStopChannel:
log.Printf("🛑 %s 波浪动画被用户停止", ifName)
return
case <-time.After(delay):
// 继续执行
}
}
// 波浪握拳
for _, idx := range fingerOrder {
pose := make([]byte, 6)
for j := 0; j < 6; j++ {
if j == idx {
pose[j] = close
} else {
pose[j] = open
}
}
if err := SendFingerPose(ifName, pose, handType, handId); err != nil {
log.Printf("%s 动画发送失败: %v", ifName, err)
return
}
delay := time.Duration(speed) * time.Millisecond
select {
case <-currentStopChannel:
log.Printf("🛑 %s 波浪动画被用户停止", ifName)
return
case <-time.After(delay):
// 继续执行
}
}
}
}
}()
}
// 执行横向摆动动画 - 支持手型参数
func StartSwayAnimation(ifName string, speed int, handType string, handId uint32) {
if speed <= 0 {
speed = 500 // 默认速度
}
// 如果未指定接口,使用默认接口
if ifName == "" {
ifName = config.Config.DefaultInterface
}
// 验证接口
if !IsValidInterface(ifName) {
log.Printf("❌ 无法启动摆动动画: 无效的接口 %s", ifName)
return
}
AnimationMutex.Lock()
if AnimationActive[ifName] {
select {
case StopAnimationMap[ifName] <- struct{}{}:
// 发送成功
default:
// 通道已满,无需发送
}
StopAnimationMap[ifName] = make(chan struct{}, 1)
}
AnimationActive[ifName] = true
AnimationMutex.Unlock()
currentStopChannel := StopAnimationMap[ifName]
go func() {
defer func() {
AnimationMutex.Lock()
AnimationActive[ifName] = false
AnimationMutex.Unlock()
log.Printf("🔄 %s 横向摆动动画已完成", ifName)
}()
leftPose := []byte{48, 48, 48, 48} // 0x30
rightPose := []byte{208, 208, 208, 208} // 0xD0
log.Printf("🚀 开始 %s 横向摆动动画", ifName)
// 动画循环
for {
select {
case <-currentStopChannel:
log.Printf("🛑 %s 横向摆动动画被用户停止", ifName)
return
default:
// 向左移动
if err := SendPalmPose(ifName, leftPose, handType, handId); err != nil {
log.Printf("%s 动画发送失败: %v", ifName, err)
return
}
delay := time.Duration(speed) * time.Millisecond
select {
case <-currentStopChannel:
log.Printf("🛑 %s 横向摆动动画被用户停止", ifName)
return
case <-time.After(delay):
// 继续执行
}
// 向右移动
if err := SendPalmPose(ifName, rightPose, handType, handId); err != nil {
log.Printf("%s 动画发送失败: %v", ifName, err)
return
}
select {
case <-currentStopChannel:
log.Printf("🛑 %s 横向摆动动画被用户停止", ifName)
return
case <-time.After(delay):
// 继续执行
}
}
}
}()
}
// 停止所有动画
func StopAllAnimations(ifName string) {
// 如果未指定接口,停止所有接口的动画
if ifName == "" {
for _, validIface := range config.Config.AvailableInterfaces {
StopAllAnimations(validIface)
}
return
}
// 验证接口
if !IsValidInterface(ifName) {
log.Printf("⚠️ 尝试停止无效接口的动画: %s", ifName)
return
}
AnimationMutex.Lock()
defer AnimationMutex.Unlock()
if AnimationActive[ifName] {
select {
case StopAnimationMap[ifName] <- struct{}{}:
log.Printf("✅ 已发送停止 %s 动画信号", ifName)
default:
StopAnimationMap[ifName] = make(chan struct{}, 1)
StopAnimationMap[ifName] <- struct{}{}
log.Printf("⚠️ %s 通道重置后发送了停止信号", ifName)
}
AnimationActive[ifName] = false
go func() {
time.Sleep(100 * time.Millisecond)
resetToDefaultPose(ifName)
}()
} else {
log.Printf(" %s 当前没有运行中的动画", ifName)
}
}
// 重置到默认姿势
func resetToDefaultPose(ifName string) {
// 如果未指定接口,重置所有接口
if ifName == "" {
for _, validIface := range config.Config.AvailableInterfaces {
resetToDefaultPose(validIface)
}
return
}
// 验证接口
if !IsValidInterface(ifName) {
log.Printf("⚠️ 尝试重置无效接口: %s", ifName)
return
}
defaultFingerPose := []byte{64, 64, 64, 64, 64, 64}
defaultPalmPose := []byte{128, 128, 128, 128}
// 获取当前接口的手型配置
handConfig := GetHandConfig(ifName)
if err := SendFingerPose(ifName, defaultFingerPose, handConfig.HandType, handConfig.HandId); err != nil {
log.Printf("%s 重置手指姿势失败: %v", ifName, err)
}
if err := SendPalmPose(ifName, defaultPalmPose, handConfig.HandType, handConfig.HandId); err != nil {
log.Printf("%s 重置掌部姿势失败: %v", ifName, err)
}
log.Printf("✅ 已重置 %s 到默认姿势", ifName)
}
// 读取传感器数据 (模拟)
func ReadSensorData() {
go func() {
for {
SensorMutex.Lock()
// 为每个接口模拟压力数据 (0-100)
for _, ifName := range config.Config.AvailableInterfaces {
if sensorData, exists := SensorDataMap[ifName]; exists {
sensorData.Thumb = rand.IntN(101)
sensorData.Index = rand.IntN(101)
sensorData.Middle = rand.IntN(101)
sensorData.Ring = rand.IntN(101)
sensorData.Pinky = rand.IntN(101)
sensorData.LastUpdate = time.Now()
}
}
SensorMutex.Unlock()
time.Sleep(500 * time.Millisecond)
}
}()
}
// 检查 CAN 服务状态
func CheckCanServiceStatus() map[string]bool {
resp, err := http.Get(config.Config.CanServiceURL + "/api/status")
if err != nil {
log.Printf("❌ CAN 服务状态检查失败: %v", err)
result := make(map[string]bool)
for _, ifName := range config.Config.AvailableInterfaces {
result[ifName] = false
}
return result
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Printf("❌ CAN 服务返回非正常状态:%d", resp.StatusCode)
result := make(map[string]bool)
for _, ifName := range config.Config.AvailableInterfaces {
result[ifName] = false
}
return result
}
var statusResp define.ApiResponse
if err := json.NewDecoder(resp.Body).Decode(&statusResp); err != nil {
log.Printf("❌ 解析 CAN 服务状态失败: %v", err)
result := make(map[string]bool)
for _, ifName := range config.Config.AvailableInterfaces {
result[ifName] = false
}
return result
}
// 检查状态数据
result := make(map[string]bool)
for _, ifName := range config.Config.AvailableInterfaces {
result[ifName] = false
}
// 从响应中获取各接口状态
if statusData, ok := statusResp.Data.(map[string]interface{}); ok {
if interfaces, ok := statusData["interfaces"].(map[string]interface{}); ok {
for ifName, ifStatus := range interfaces {
if status, ok := ifStatus.(map[string]interface{}); ok {
if active, ok := status["active"].(bool); ok {
result[ifName] = active
}
}
}
}
}
return result
}