4. SDK接口调用说明 
4.1 核心类和方法 
4.1.1 命名空间 
cpp
namespace psi_glove {
    class SerialInterface;
    class PSIGloveController;
    struct StatusMessage;
    class CommunicationInterface;  // 抽象基类
}4.1.2 SerialInterface 类 
串口通信接口类,处理底层硬件通信。
cpp
#include <psi_glove_sdk/serial_interface.hpp>
namespace psi_glove {
class SerialInterface : public CommunicationInterface {
public:
    // 构造函数
    SerialInterface(
        const std::string& port,
        int baudrate = 115200,
        std::chrono::milliseconds timeout = std::chrono::milliseconds(6),
        bool auto_connect = false,
        bool mock = false
    );
    
    // 析构函数(自动断开连接)
    ~SerialInterface() override;
    
    // 连接/断开
    bool Connect() override;
    bool Disconnect() override;
    bool IsConnected() const override;
    
    // 数据传输
    bool Write(const std::vector<uint8_t>& data) override;
    bool Read(std::vector<uint8_t>& data, size_t size) override;
};
}  // namespace psi_glove4.1.3 PSIGloveController 类 
主控制器类,管理数据读取、解析和平滑处理。
cpp
#include <psi_glove_sdk/psi_glove_controller.hpp>
namespace psi_glove {
class PSIGloveController {
public:
    // 构造函数
    PSIGloveController(
        std::unique_ptr<CommunicationInterface> interface,
        size_t smoothing_window_size = 10
    );
    
    // 析构函数
    ~PSIGloveController();
    
    // 连接管理
    bool Connect();
    bool Disconnect();
    bool IsConnected() const;
    
    // 数据读取
    std::optional<StatusMessage> Loop();
    std::optional<StatusMessage> GetLastStatus() const;
    
private:
    // 内部实现(用户无需关注)
    class Impl;
    std::unique_ptr<Impl> pimpl_;
};
}  // namespace psi_glove核心方法说明:
| 方法名称 | 返回类型 | 功能说明 | 
|---|---|---|
Connect() | bool | 连接设备,成功返回 true | 
Disconnect() | bool | 断开设备连接 | 
IsConnected() | bool | 检查是否已连接 | 
Loop() | std::optional<StatusMessage> | 读取并返回关节数据,失败返回 std::nullopt | 
GetLastStatus() | std::optional<StatusMessage> | 获取最后一次成功读取的数据 | 
4.1.4 StatusMessage 结构 
包含 21 个关节位置的数据结构。
cpp
#include <psi_glove_sdk/types.hpp>
namespace psi_glove {
struct StatusMessage {
    std::array<uint16_t, 5> thumb;   // 拇指:5 个关节
    std::array<uint16_t, 4> index;   // 食指:4 个关节
    std::array<uint16_t, 4> middle;  // 中指:4 个关节
    std::array<uint16_t, 4> ring;    // 无名指:4 个关节
    std::array<uint16_t, 4> pinky;   // 小指:4 个关节
    
    // 辅助方法
    std::vector<uint16_t> ToVector() const;  // 转换为扁平向量(21个值)
};
}  // namespace psi_glove4.2 读取主手数据的完整流程 
4.2.1 最小示例 
cpp
#include <psi_glove_sdk/psi_glove.hpp>
#include <iostream>
#include <thread>
#include <chrono>
int main() {
    // 1. 创建串口接口
    auto serial = std::make_unique<psi_glove::SerialInterface>(
        "/dev/ttyACM0",  // 串口路径
        115200           // 波特率
    );
    
    // 2. 创建控制器
    psi_glove::PSIGloveController controller(std::move(serial), 10);
    
    // 3. 连接设备
    if (!controller.Connect()) {
        std::cerr << "连接失败" << std::endl;
        return 1;
    }
    
    // 4. 循环读取数据
    for (int i = 0; i < 100; ++i) {
        auto status = controller.Loop();
        
        if (status) {
            // 访问关节数据
            std::cout << "拇指第一关节: " << status->thumb[0] << std::endl;
        }
        
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    
    // 5. 断开连接(或让析构函数自动处理)
    controller.Disconnect();
    
    return 0;
}4.2.2 完整示例(带错误处理) 
cpp
#include <psi_glove_sdk/psi_glove.hpp>
#include <iostream>
#include <thread>
#include <chrono>
#include <signal.h>
#include <atomic>
// 全局退出标志
std::atomic<bool> g_running{true};
void SignalHandler(int signal) {
    g_running.store(false);
    std::cout << "\n正在退出..." << std::endl;
}
int main(int argc, char** argv) {
    // 设置信号处理
    signal(SIGINT, SignalHandler);
    
    // 解析命令行参数
    std::string port = (argc > 1) ? argv[1] : "/dev/ttyUSB0";
    int baudrate = (argc > 2) ? std::atoi(argv[2]) : 115200;
    
    try {
        // 1. 创建串口接口
        auto serial = std::make_unique<psi_glove::SerialInterface>(
            port,
            baudrate,
            std::chrono::milliseconds(6),
            false,  // 不自动连接
            false   // 不使用模拟模式
        );
        
        // 2. 创建控制器
        psi_glove::PSIGloveController controller(std::move(serial), 10);
        
        // 3. 连接设备
        std::cout << "正在连接到 " << port << "..." << std::endl;
        if (!controller.Connect()) {
            std::cerr << "错误: 无法连接到设备" << std::endl;
            std::cerr << "请检查:" << std::endl;
            std::cerr << "  - 设备是否已连接" << std::endl;
            std::cerr << "  - 串口路径是否正确" << std::endl;
            std::cerr << "  - 是否有权限访问串口" << std::endl;
            return 1;
        }
        std::cout << "连接成功!" << std::endl;
        
        // 4. 主循环 - 读取关节数据
        int frame_count = 0;
        auto start_time = std::chrono::steady_clock::now();
        
        while (g_running && controller.IsConnected()) {
            // 读取数据
            auto status = controller.Loop();
            
            if (status) {
                // 成功读取数据
                if (frame_count % 10 == 0) {
                    std::cout << "\n--- 帧 #" << frame_count << " ---" << std::endl;
                    
                    // 打印拇指数据
                    std::cout << "拇指: ";
                    for (size_t i = 0; i < status->thumb.size(); ++i) {
                        std::cout << status->thumb[i];
                        if (i < status->thumb.size() - 1) std::cout << ", ";
                    }
                    std::cout << std::endl;
                    
                    // 打印食指数据
                    std::cout << "食指: ";
                    for (size_t i = 0; i < status->index.size(); ++i) {
                        std::cout << status->index[i];
                        if (i < status->index.size() - 1) std::cout << ", ";
                    }
                    std::cout << std::endl;
                    
                    // 其他手指...
                }
                
                frame_count++;
            } else {
                // 读取失败
                std::cerr << "警告: 读取失败,使用缓存数据" << std::endl;
                
                // 尝试获取最后一次成功的数据
                auto last_status = controller.GetLastStatus();
                if (last_status) {
                    std::cout << "(使用上次的有效数据)" << std::endl;
                }
            }
            
            // 控制循环频率 (约100Hz)
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
        
        // 计算统计信息
        auto end_time = std::chrono::steady_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::seconds>(
            end_time - start_time
        );
        
        std::cout << "\n统计信息:" << std::endl;
        std::cout << "  总帧数: " << frame_count << std::endl;
        std::cout << "  运行时间: " << duration.count() << " 秒" << std::endl;
        if (duration.count() > 0) {
            double fps = frame_count / static_cast<double>(duration.count());
            std::cout << "  平均帧率: " << fps << " Hz" << std::endl;
        }
        
        // 5. 断开连接
        controller.Disconnect();
        std::cout << "已断开连接。" << std::endl;
        
    } catch (const std::exception& e) {
        std::cerr << "异常: " << e.what() << std::endl;
        return 1;
    }
    
    return 0;
}4.3 数据格式和单位 
关节索引映射 
| 手指 | 关节数量 | 索引范围 | 访问方式 | 
|---|---|---|---|
| 拇指 | 5 | 0-4 | status.thumb[0-4] | 
| 食指 | 4 | 5-8 | status.index[0-3] | 
| 中指 | 4 | 9-12 | status.middle[0-3] | 
| 无名指 | 4 | 13-16 | status.ring[0-3] | 
| 小指 | 4 | 17-20 | status.pinky[0-3] | 
数据单位和范围 
- 数据类型: 
uint16_t(无符号16位整数) - 数值范围: 
0 - 4095(12位 ADC) - 物理含义: 关节传感器的电压值(经过模数转换)
 - 数值对应: 
0: 传感器最小值(手指完全伸直)2048: 传感器中间值4095: 传感器最大值(手指完全弯曲)
 
数据处理示例 
cpp
// 归一化到 0.0 - 1.0 范围
inline double NormalizeJoint(uint16_t value) {
    return static_cast<double>(value) / 4095.0;
}
// 映射到角度(需要校准)
inline double ADCToAngle(
    uint16_t value,
    uint16_t min_adc,
    uint16_t max_adc,
    double min_angle,
    double max_angle
) {
    double normalized = static_cast<double>(value - min_adc) / 
                        (max_adc - min_adc);
    return min_angle + normalized * (max_angle - min_angle);
}
// 使用示例
auto status = controller.Loop();
if (status) {
    // 归一化拇指第一关节
    double normalized = NormalizeJoint(status->thumb[0]);
    std::cout << "归一化值: " << normalized << std::endl;
    
    // 映射到角度(假设校准范围)
    double angle = ADCToAngle(status->thumb[0], 500, 3500, 0.0, 90.0);
    std::cout << "关节角度: " << angle << "°" << std::endl;
}4.4 高级用法示例 
4.4.1 批量数据采集 
cpp
#include <psi_glove_sdk/psi_glove.hpp>
#include <fstream>
#include <vector>
#include <thread>
#include <chrono>
int main() {
    // 初始化
    auto serial = std::make_unique<psi_glove::SerialInterface>("/dev/ttyACM0", 115200);
    psi_glove::PSIGloveController controller(std::move(serial), 10);
    controller.Connect();
    
    // 采集 1000 帧数据
    std::vector<std::vector<uint16_t>> data_buffer;
    data_buffer.reserve(1000);
    
    for (int i = 0; i < 1000; ++i) {
        auto status = controller.Loop();
        if (status) {
            data_buffer.push_back(status->ToVector());
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    
    // 保存到 CSV
    std::ofstream file("glove_data.csv");
    // 表头
    for (int i = 0; i < 21; ++i) {
        file << "joint_" << i;
        if (i < 20) file << ",";
    }
    file << "\n";
    
    // 数据
    for (const auto& row : data_buffer) {
        for (size_t i = 0; i < row.size(); ++i) {
            file << row[i];
            if (i < row.size() - 1) file << ",";
        }
        file << "\n";
    }
    
    std::cout << "已保存 " << data_buffer.size() << " 帧数据到 glove_data.csv" << std::endl;
    
    controller.Disconnect();
    return 0;
}4.4.2 多手套同时使用 
cpp
#include <psi_glove_sdk/psi_glove.hpp>
#include <iostream>
#include <thread>
#include <chrono>
int main() {
    // 左手
    auto left_serial = std::make_unique<psi_glove::SerialInterface>("/dev/ttyACM0", 115200);
    psi_glove::PSIGloveController left_controller(std::move(left_serial), 10);
    left_controller.Connect();
    
    // 右手
    auto right_serial = std::make_unique<psi_glove::SerialInterface>("/dev/ttyACM1", 115200);
    psi_glove::PSIGloveController right_controller(std::move(right_serial), 10);
    right_controller.Connect();
    
    // 同时读取双手数据
    for (int i = 0; i < 100; ++i) {
        auto left_status = left_controller.Loop();
        auto right_status = right_controller.Loop();
        
        if (left_status && right_status) {
            std::cout << "左手拇指: " << left_status->thumb[0] 
                      << ", 右手拇指: " << right_status->thumb[0] << std::endl;
        }
        
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    
    left_controller.Disconnect();
    right_controller.Disconnect();
    
    return 0;
}