站内搜索
更多
机甲小师
专业版

机甲小师

简介

参考RoboMaster英雄机器人设计的丐版,可视化操作界面、可支持人脸识别解锁与自动锁头,配合二维云台发射激光武器等功能,配合全向麦轮底盘,打造一个预算有限成本极低的“机甲小师”!

简介:参考RoboMaster英雄机器人设计的丐版,可视化操作界面、可支持人脸识别解锁与自动锁头,配合二维云台发射激光武器等功能,配合全向麦轮底盘,打造一个预算有限成本极低的“机甲小师”!
立创开发板「课设/毕设」开源计划
复刻成本:400

开源协议

GPL 3.0

创建时间:2025-10-27 14:31:44更新时间:2025-11-27 16:18:26

描述

题目要求

机甲小师

题目分析

参考RoboMaster英雄机器人设计的丐版,可视化操作界面、模式切换、可支持人脸识别解锁与自动锁头、纯视觉测距,配合二维云台发射激光武器等功能,配合全向麦轮底盘,打造一个预算有限成本极低的“机甲小师”!另外,在经济条件允许的情况下,还可以拓展更多控制机构(比如上下位机加装六自由度的旋转电位器控制机械臂、水弹枪...)、增加实时图传,设计基本可以涵盖STM32F103c8t6常用的片上外设、基础的机器视觉算法、基础的运动控制算法、滤波算法、还涉及多端代码联调、模块选型等。可以作为一个基础的练手项目!!!

后期计划打造一个完整的满血“机甲小师”:不依赖模块的高度集成化、更精准的控制机构、全3D打印炫酷外壳、多种武器选择、无线图传+屏幕直控等,敬请期待

总体设计方案框图

流程图.png

原理图设计说明

发送与接收端均通过STM32引脚特性进行了简单的引脚分配,配合拓展接口直接与各模块连接,大大降低了开发难度

发送端原理图.png

接收端原理图.png

PCB设计说明

遥控器PCB部分

发送端PCB.jpg
主控PCB
接收端PCB.jpg

第一代版本基本都是使用的电路模块,设计简单制作较为方便而且容错较高,发送端的板框按实际的串口屏尺寸做的,不同方案需要自行设计相应的尺寸。

软件说明

摄像头端:使用嘉楠科技的CanMV IDE K230开发,示例程序在立创官方的网站https://wiki.lckfb.com/zh-hans/lushan-pi-k230/ 可以找到(有好多好玩的例程,稍加改造就有很不错的效果!!!),本次开发借鉴了其中人脸识别和人体关键点检测,如果有其他识别需求也可以在这里面找找;

image.png
发送端&接收端:基于keil标准库进行开发
串口屏:使用陶晶驰官方开发软件USART HMI进行相关开发

image.png

代码块:
舵机控制方面,接收到摄像头采集的目标坐标信息后,通过多级步长调节控制舵机在不同位置采用不同的速度,相较于PID来说,大大降低了部署难度,有很不错的鲁棒性

*舵机参数自定义
    
// 三级速度分区阈值,XY独立配置
#define LOOP_DELAY_MS     5      
#define IMPROVE_THRESHOLD 0.3f    
#define DATA_WINDOW_SIZE  3       
#define DEAD_ZONE 0.5f          
// X轴速度分区阈值(独立):±5外=步长3,±2~±5=步长2,±2内=步长1
#define X_FAR_THRESHOLD   5.0f    // X轴远距阈值
#define X_NEAR_THRESHOLD  2.0f    // X轴近距阈值
// Y轴速度分区阈值(独立):±5外=步长3,±2~±5=步长2,±2内=步长1
#define Y_FAR_THRESHOLD   5.0f    // Y轴远距阈值
#define Y_NEAR_THRESHOLD  2.0f    // Y轴近距阈值
// 三级步长定义
#define STEP_FAST  4 // 快速步长(远距)
#define STEP_MID   2 // 中速步长(中距)
#define STEP_SLOW  1 // 慢速步长(近距)

// -------------------------- X轴动态调整(三级速度,独立控制)--------------------------
if (fabs(filt_x) > DEAD_ZONE) {
    float delta_x = fabs(filt_x) - fabs(last_filtered_x);
    int current_step = STEP_SLOW;  // 默认慢速
    
    // 根据X轴距离选择步长
    if (fabs(filt_x) > X_FAR_THRESHOLD) {
        current_step = STEP_FAST;
    } else if (fabs(filt_x) > X_NEAR_THRESHOLD) {
        current_step = STEP_MID;
    }

    if (filt_x > 0) {
        // 目标在中心右侧(X正):右转(角度减小)
        if (delta_x < -IMPROVE_THRESHOLD) {
            servo_x_angle = limit_angle(servo_x_angle - current_step, 1, 179);
        } else if (delta_x > IMPROVE_THRESHOLD) {
            servo_x_angle = limit_angle(servo_x_angle - current_step, 1, 179);
        } else {
            // 坐标稳定:步长减半,避免过冲
            servo_x_angle = limit_angle(servo_x_angle - (current_step / 2), 1, 179);
        }
    } else {
        // 目标在中心左侧(X负):左转(角度增大)
        if (delta_x < -IMPROVE_THRESHOLD) {
            servo_x_angle = limit_angle(servo_x_angle + current_step, 1, 179);
        } else if (delta_x > IMPROVE_THRESHOLD) {
            servo_x_angle = limit_angle(servo_x_angle + current_step, 1, 179);
        } else {
            servo_x_angle = limit_angle(servo_x_angle + (current_step / 2), 30, 179);
        }
    }
}

// -------------------------- Y轴动态调整(三级速度,独立控制)--------------------------
if (fabs(filt_y) > DEAD_ZONE) {
    float delta_y = fabs(filt_y) - fabs(last_filtered_y);
    int current_step = STEP_SLOW;  // 默认慢速
    
    // 根据Y轴距离选择步长
    if (fabs(filt_y) > Y_FAR_THRESHOLD) {
        current_step = STEP_FAST;
    } else if (fabs(filt_y) > Y_NEAR_THRESHOLD) {
        current_step = STEP_MID;
    }

    if (filt_y > 0) {
        // 目标在中心下方(Y正):上转(角度增大)
        if (delta_y < -IMPROVE_THRESHOLD) {
            servo_y_angle = limit_angle(servo_y_angle + current_step, 30, 179);
        } else if (delta_y > IMPROVE_THRESHOLD) {
            servo_y_angle = limit_angle(servo_y_angle + current_step, 30, 179);
        } else {
            servo_y_angle = limit_angle(servo_y_angle + (current_step / 2), 30, 179);
        }
    } else {
        // 目标在中心上方(Y负):下转(角度减小)
        if (delta_y < -IMPROVE_THRESHOLD) {
            servo_y_angle = limit_angle(servo_y_angle - current_step, 30, 179);
        } else if (delta_y > IMPROVE_THRESHOLD) {
            servo_y_angle = limit_angle(servo_y_angle - current_step, 30, 179);
        } else {
            servo_y_angle = limit_angle(servo_y_angle - (current_step / 2),30, 179);
        }
    }
}

视觉处理部分代码

视觉方面,距离检测是基于立创·庐山派K230官方文档里的“人体关键点检测”改造而成的:通过计算肩部关键点与耳朵关键点的像素距离,与正常人类的平均长度推导出当前距离;由于时间问题,代码这里仅做一个大致的推算演示,精度不是很高,如果想更精进,可以多加几组(比如肩宽、臂长等)
```
import math

EAR_TO_SHOULDER_CM = 20  # 耳到肩实际物理距离(cm)
FOCAL_LENGTH = 900       # 摄像头焦距(像素)
KEYPOINT_CONF_THRESH = 0.3  # 关键点置信度阈值

def calc_person_distance(kpses):
"""
单目测距逻辑
:param kpses: 模型输出关键点 [person_idx][kp_idx][x, y, confidence]
:return: 实际距离(cm),无效返回None
"""
# 关键点索引
left_ear = kpses[0][3]    # 左耳(索引3)
left_shoulder = kpses[0][5]# 左肩(索引5)
right_ear = kpses[0][4]   # 右耳(索引4)
right_shoulder = kpses[0][6]# 右肩(索引6)

# 过滤低置信度关键点
valid_pairs = []
if left_ear[2] > KEYPOINT_CONF_THRESH and left_shoulder[2] > KEYPOINT_CONF_THRESH:
    valid_pairs.append((left_ear, left_shoulder))
if right_ear[2] > KEYPOINT_CONF_THRESH and right_shoulder[2] > KEYPOINT_CONF_THRESH:
    valid_pairs.append((right_ear, right_shoulder))

if not valid_pairs:
    return None

# 计算平均像素距离
total_pixel_dist = 0
for (kp1, kp2) in valid_pairs:
    # 像素
    pixel_dist = math.hypot(kp2[0]-kp1[0], kp2[1]-kp1[1])
    total_pixel_dist += pixel_dist
avg_pixel_dist = total_pixel_dist / len(valid_pairs)

# 实际距离 = (物理尺寸 × 焦距) / 像素距离
return (EAR_TO_SHOULDER_CM * FOCAL_LENGTH) / avg_pixel_dist

这里有个比较有意思的代码,时摇杆的一个初始化校准,因为它默认状态下电位偏的特别离谱,因此加了一个校准功能:上电后读取此时的XY轴的电位,将此时的电位作为中间值重新计算两侧的电位值

static void Joystick_AutoCalibrate(void)
{
    Delay_Ms(200);
    uint32_t x_sum = 0, y_sum = 0;
    for (uint8_t i = 0; i < 5; i++)
    {
        x_sum += ADC_ReadChannel(ADC_Channel_1);  // X=A1
        y_sum += ADC_ReadChannel(ADC_Channel_0);  // Y=A0
        Delay_Ms(10);
    }
    uint16_t x_center = x_sum / 5;
    uint16_t y_center = y_sum / 5;
    x_offset = x_center - JOY_CALIB_MID;
    y_offset = y_center - JOY_CALIB_MID;
}

// 摇杆数据(读取+校准+处理)
void Joystick_Update(JoystickData *data) {
    // 读取原始ADC值
    uint16_t x_raw = ADC_ReadChannel(ADC_Channel_1);
    uint16_t y_raw = ADC_ReadChannel(ADC_Channel_0);
    
    // 应用校准并限制范围
    int32_t x_calibrated = (int32_t)x_raw - x_offset;
    data->x_raw = (x_calibrated < 0) ? 0 : (x_calibrated > ADC_MAX) ? ADC_MAX : (uint16_t)x_calibrated;
    
    int32_t y_calibrated = (int32_t)y_raw - y_offset;
    data->y_raw = (y_calibrated < 0) ? 0 : (y_calibrated > ADC_MAX) ? ADC_MAX : (uint16_t)y_calibrated;
    
    // 计算角度
    data->x_angle = (uint8_t)((data->x_raw * 180.0f) / ADC_MAX);
    data->y_angle = (uint8_t)((data->y_raw * 180.0f) / ADC_MAX);
}

实物展示说明

第一代版本全家福.jpg

发送端串口屏部分UI
发送端实物图.jpg

后面又做了简单的外壳,,,就是它的头怎么大大的

外观改动.jpg

注意事项

发送端的STM32是焊在反面的,注意不要搞错了
舵机安装前要确保初始角度均在90°的位置
串口通信注意配置合适的波特率、TR不要接错

##硬件选型

硬件选型.jpg

演示视频

【立创开源活动-哔哩哔哩】 https://b23.tv/IaBH3O6

其它附件上传

通过网盘分享的文件:机甲小师开源资料.zip
链接: https://pan.baidu.com/s/1gqt7Km1rPFPJojcqwo31qw 提取码: 0717

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

3D模型

序号文件名称下载次数
暂无数据

附件

序号文件名称下载次数
暂无数据
克隆工程
添加到专辑
0
0
分享
侵权投诉
知识产权声明&复刻说明

本项目为开源硬件项目,其相关的知识产权归创作者所有。创作者在本平台上传该硬件项目仅供平台用户用于学习交流及研究,不包括任何商业性使用,请勿用于商业售卖或其他盈利性的用途;如您认为本项目涉嫌侵犯了您的相关权益,请点击上方“侵权投诉”按钮,我们将按照嘉立创《侵权投诉与申诉规则》进行处理。

请在进行项目复刻时自行验证电路的可行性,并自行辨别该项目是否对您适用。您对复刻项目的任何后果负责,无论何种情况,本平台将不对您在复刻项目时,遇到的任何因开源项目电路设计问题所导致的直接、间接等损害负责。

底部导航