一个超酷的开源uHand2.0机械手掌项目

简介: 一个超酷的开源uHand2.0机械手掌项目

uHand2.0是深圳乐幻索尔公司开源的一款机械手掌,它长下面这个样子:

1、uHand2.0外观图

640.jpg

之前在公众号就分享过视频:


学习嵌入式可以带娃,不信你们看

2、uHand2.0硬件原理图

看似整体非常复杂(主要是结构),但其实硬件(指电路部分)、软件一点都不复杂,我们来看下控制机械手掌的电路原理图,控制部分的芯片采用的STM32F103RBT6

640.png

底板对接的原理图如下:

640.png

640.png

可以看到,以上这些都是我们熟悉的硬件接口,包含LED、蜂鸣器、按键、SPI FLASH、舵机、PS2,控制机械手掌根据官方提供的文档主要四种方式:


  • 1、通过PC串口连接C#上位机控制机械手掌
  • 2、通过体感手套蓝牙模块连接机械手掌进行控制
  • 3、通过Android手机APP控制机械手掌
  • 4、通过PS2手柄控制机械手掌


不管是通过什么方式去控制手掌运动,能有一套公有的通信协议那就再好不过了,那么uHand2.0对这一套协议也是完全开源的,我们来阅读一些基础协议,以便于我们后面入门各个软件程序。

3、uHand2.0通信协议

640.png

其中,通信分为两种:


  • 1、用户主动通过C#上位机、PS2、PC、APP主动给控制板发送数据
  • 2、控制板主动给C#上位机、PS2、PC、APP发送数据


具体协议内容请公众号后台回复:uHand获取开源机械手掌资料,这里就不细说了。

4、uHand2.0底板控制部分

官方给出的有两种控制方式,一种是基于STM32、还有一种是基于51单片机,不管是什么平台控制,软件逻辑其实都是大同小异,我们就拿常用的STM32软件进行分析吧。


先看下代码的整体框架:

int main(void)
{
 SystemInit();     //系统时钟初始化为72M   SYSCLK_FREQ_72MHz
 InitDelay(72);      //延时初始化
    //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
 InitPWM();
 InitTimer2();//用于产生100us的定时中断
 InitUart1();//用于与PC端进行通信
 InitUart3();//外接模块的串口
 InitADC();
 InitLED();
 InitKey();
 InitBuzzer();
 InitPS2();//PS2游戏手柄接收器初始化
 InitFlash();
 InitMemory();
 InitBusServoCtrl();
 LED = LED_ON;
 BusServoCtrl(1,SERVO_MOVE_TIME_WRITE,500,1000);
 BusServoCtrl(2,SERVO_MOVE_TIME_WRITE,500,1000);
 BusServoCtrl(3,SERVO_MOVE_TIME_WRITE,500,1000);
 BusServoCtrl(4,SERVO_MOVE_TIME_WRITE,500,1000);
 BusServoCtrl(5,SERVO_MOVE_TIME_WRITE,500,1000);
 BusServoCtrl(6,SERVO_MOVE_TIME_WRITE,500,1000);
 while(1)
 {
  TaskRun();
 }
}

由于机械手掌采用是总线舵机,其实它就是数字舵机,是基于串行总线开发的,通常采用一根线就可以完成发送和接收的操作,十分方便,详情可以参考开源机械手掌的资料,这里我们看一下BusServoCtrl这个函数实现的功能:

void BusServoCtrl(uint8 id,uint8 cmd,uint16 prm1,uint16 prm2)
{
 uint32 i;
 uint8 tx[20];
 uint8 datalLen = 4;
 uint32 checkSum = 0;
 switch(cmd)
 {
 case SERVO_MOVE_TIME_WRITE:
  datalLen = SERVO_MOVE_TIME_DATA_LEN;
  break;
 }
 tx[0] = 0x55;
 tx[1] = 0x55;
 tx[2] = id;
 tx[3] = datalLen;
 tx[4] = cmd;
 tx[5] = prm1;
 tx[6] = prm1 >> 8;
 tx[7] = prm2;
 tx[8] = prm2 >> 8;
 for(i = 2; i <= datalLen + 1; i++)
 {
  checkSum += tx[i];
 }
 tx[datalLen + 2] = ~checkSum;
 UART_TX_ENABLE();
 USART2SendDataPacket(tx,datalLen + 3);
}

该函数的第一个参数为舵机id,第二个参数为指令,第三、四个参数为指令的参数,例如要控制数字电机转动,则需要设置prm1和prm2值,以让舵机能够在具体的时间内转动到具体的位置,最终通过串口将协议数据发送到数字舵机,这时候舵机接收到指令则会响应具体的操作,这个函数是贯穿整个机械手掌运动的核心函数。


如果通过C#上位机、APP控制机械手掌,那么也是一样的,C#上位机发送给控制板的USART1串口,我们重点看下USART1的串口中断服务函数的实现:

void USART1_IRQHandler(void)
{
    uint8 i;
    uint8 rxBuf;
    static uint8 startCodeSum = 0;
    static bool fFrameStart = FALSE;
    static uint8 messageLength = 0;
    static uint8 messageLengthSum = 2;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        rxBuf = USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
        if(!fFrameStart)
        {
            if(rxBuf == 0x55)
            {
                startCodeSum++;
                if(startCodeSum == 2)
                {
                    startCodeSum = 0;
                    fFrameStart = TRUE;
                    messageLength = 1;
                }
            }
            else
            {
                fFrameStart = FALSE;
                messageLength = 0;
                startCodeSum = 0;
            }
        }
        if(fFrameStart)
        {
            Uart1RxBuffer[messageLength] = rxBuf;
            if(messageLength == 2)
            {
                messageLengthSum = Uart1RxBuffer[messageLength];
                if(messageLengthSum < 2)// || messageLengthSum > 30
                {
                    messageLengthSum = 2;
                    fFrameStart = FALSE;
                }
            }
            messageLength++;
            if(messageLength == messageLengthSum + 2)
            {
                if(fUartRxComplete == FALSE)
                {
                    fUartRxComplete = TRUE;
                    for(i = 0; i < messageLength; i++)
                    {
                        UartRxBuffer[i] = Uart1RxBuffer[i];
                    }
                }
                fFrameStart = FALSE;
            }
        }
    }
}

中断服务函数实现的功能就是将上位机、APP、PS2所发送的数据根据第三小节提到的协议格式转换成控制串口舵机的指令,这个过程是在TaskRun函数实现的,由于代码过于冗长,这里就不放出来了,感兴趣可以自行下载研究。另外,该代码的优化空间很大,有些部分写得不是太合理。

5、uHand2.0开源上位机

上位机采用的是C# 微软WPF框架开发,通过PC串口与机械手掌进行通信。

5.1、分析代码

当调整拖动杆时,调用anleChangeHandler方法:

private void angleChangeHandler(Object sender, RoutedEventArgs e)
{
     //手动拖动滑竿的时候才触发,其他情况引起的变化屏蔽
     if (needSendAngelChangeFlag)
     {
        int id = Convert.ToInt32((e.OriginalSource as ServoView).ServoId);
        int angle = (e.OriginalSource as ServoView).CurAngle;
        sendAngleCmd(id, angle);
     }
}

该方法首先会先确定当时控制的是哪个ID的拖杆,调整的数值是多少,最终调用sendAngleCmd方法:

//发送拖到滑竿引起的角度变化设置命令
private void sendAngleCmd(int id, int value)
{
    UInt16[] dataSend = new UInt16[MAX_ARGS_LENTH];
    for (int i = 0; i < MAX_ARGS_LENTH; i++)
    {
        dataSend[i] = UNDEFINECMD;
    }
    dataSend[0] = 1;
    dataSend[1] = 0;
    dataSend[2] = 0;
    dataSend[3] = (byte)id;
    dataSend[4] = (byte)(value & 0x00ff);
    dataSend[5] = (byte)(value >> 8);
    makeAndSendCmd(CMD_MULT_SERVO_MOVE, dataSend);
}

UNDEFINECMD为public const UInt16 UNDEFINECMD = 0xFFFF;表示命令buffer默认参数。


MAX_ARGS_LENTH为public const int MAX_ARGS_LENTH = 25;表示最大的命令长度


最后通过调用makeAndSendCmd将指令打包成为标准的通信协议包,通过串口发送给控制板,进而控制机械手掌运动。

//处理参数转换成标准命令协议格式然后发送
private void makeAndSendCmd(int cmdType, UInt16[] args)
{
    //sendingData = true;
    byte[] dataSend = new byte[50];
    byte lenth;
    dataSend[0] = 0x55;
    dataSend[1] = 0x55;
    dataSend[3] = (byte)cmdType;
    int i = 0;
    while (i <= MAX_ARGS_LENTH && args[i] != UNDEFINECMD)
    {
        dataSend[4 + i] = (byte)args[i];
        i++;
    }
    lenth = (byte)(i + 2);
    //填入长度信息
    dataSend[2] = lenth;
    WriteData(dataSend, lenth + 2);
}

那么其它几种控制方式也就大同小异了。获取所有开源资料请公众号后台回复:uHand获取开源机械手掌资料。


搞懂了机械手掌的基本原理,那么后面要实现一些非常酷的项目就很容易啦,比如机械手掌控制小车等等,敬请期待!

往期精彩

一些实用的C语言小技巧


由static来谈谈模块封装


C语言常用的一些转换工具函数收集


结构体对齐原则在自定义协议解析时的妙用之法

目录
相关文章
|
7月前
|
存储 人工智能 安全
AI 智能体的标准开发流程
AI智能体开发强调自主性与闭环控制,2026年已普遍采用ADLC架构。涵盖目标建模、工具集成、记忆设计、多智能体编排、安全评估及持续进化六大环节,实现可控、可信、可进化的“数字员工”。
|
5月前
|
存储 人工智能 运维
十大 AI Agent Memory记忆系统全维度横评 主流方案架构、性能与场景选型指南
随着AI Agent从基础问答工具进化为可执行复杂长周期任务的智能体,记忆能力已经成为决定智能体上限的核心要素。传统基于向量数据库与RAG检索的技术方案,仅能实现简单信息检索,并不具备完整的记忆管理能力,在时序追踪、多代理一致性、分层存储、智能路由等方面存在明显短板。在实际生产环境中,大量AI Agent将近八成以上的计算资源消耗在重复梳理上下文信息上,真正用于业务执行的资源占比极低,这也是当前智能体规模化落地的核心瓶颈。
2739 2
|
7月前
|
Java
Abaqus 2026 安装教程:JDK配置+汉化详解(64位)
Abaqus 2026 是一款专业非线性有限元分析软件,支持材料、几何及边界非线性问题。本教程详述离线安装全流程:含JDK21配置、License部署、CAE/Standard/Explicit模块安装、环境变量设置及简体中文界面启用,操作清晰、一步一图。(239字)
|
7月前
|
机器学习/深度学习 人工智能 监控
电梯内自行车与电动车目标检测数据集分享(适用于YOLO系列深度学习分类检测任务)
本数据集含28,000张真实电梯监控图像,精准标注自行车与电动车两类目标,采用YOLO格式,专为YOLO等目标检测模型训练设计,助力智慧社区实现电动车入梯智能识别与实时预警。
753 0
|
JavaScript 关系型数据库 Linux
|
JSON 文字识别 测试技术
Qwen2.5-VL Cookbook来啦!手把手教你怎么用好视觉理解模型!
今天,Qwen团队发布了一系列展示 Qwen2.5-VL 用例的Notebook,包含本地模型和 API 的使用。
4156 22
|
机器学习/深度学习 人工智能 数据处理
[python 技巧] 快速掌握Streamlit: python快速原型开发工具
本文旨在快速上手python的streamlit库,包括安装,输入数据,绘制图表,基础控件,进度条,免费部署。
2283 64
[python 技巧] 快速掌握Streamlit: python快速原型开发工具
|
存储 监控 安全
工业物联网关应用:PLC数据通过智能网关上传阿里云实战
本文介绍如何使用智能网关将工厂PLC数据传输至阿里云平台,适合中小企业远程监控设备状态。硬件准备包括三菱FX3U PLC、4G智能网关和24V电源。接线步骤涵盖PLC编程口与网关连接、运行状态检测及天线电源接入。配置过程涉及通讯参数、阿里云对接和数据点映射。PLC程序关键点包括数据上传触发和温度值处理。阿里云平台操作包含实时数据查看、数据可视化和规则引擎设置。最后提供常见故障排查表和安全建议,确保系统稳定运行。
1999 1
|
传感器 机器人 芯片
实例4:树莓派GPIO控制舵机转动
本文是关于使用树莓派GPIO控制舵机转动的实验教程,涵盖了舵机的基本概念、结构、工作原理以及PWM信号控制方法。实验目的是通过Python编程,实现树莓派控制舵机在0°~180°范围内周期性转动。文中提供了详细的实验步骤、代码示例以及舵机调零和校准的方法。
2190 1
实例4:树莓派GPIO控制舵机转动
|
Linux 网络安全 数据安全/隐私保护
以无头模式运行 Raspberry pi
无头模式下的Raspberry Pi无需连接显示器、键盘和鼠标,通过网络远程访问进行操作,适合服务器或自动化项目。配置简单,只需在SD卡中添加特定文件即可启用SSH和Wi-Fi。
1880 1