欢迎光临
我们一直在努力

桌面宠物机器人全栈设计

在快节奏的生活中,一只可爱的桌面宠物或许是解压的最佳伙伴。市面上的电子宠物大多功能单一、不可编程,而专业机器人平台又价格高昂、门槛过高。本项目基于深圳大夏龙雀科技 BT36 蓝牙模块与 STM32F103C6T6A 主控,仅用面包板 + 杜邦线 + 4个SG90舵机 + 一块OLED屏 + 一节18650电池,就打造出一只可蓝牙遥控、会做表情、能动作卖萌的桌面宠物机器人。配套开发了微信小程序作为控制端,实现了从硬件到软件的全栈设计。


一、项目背景

1.1 创作初衷

一直想做一个既有技术含量又充满趣味的DIY项目。工业类项目虽然硬核但缺乏传播力,纯玩具类又显得技术深度不足。最终选择了"桌面宠物机器人"这个方向——

  • 趣味性强:可爱的外形、多种表情、跳舞卖萌,天然适合展示分享;

  • 技术覆盖全:涉及嵌入式开发、蓝牙通信、PWM舵机控制、I2C显示驱动、微信小程序开发,技术栈完整;

  • 门槛低可复制:面包板搭建、耗材便宜、结构简单,读者跟着教程就能复刻;

1.2 核心功能

功能模块

具体功能

运动控制

前进 / 后退 / 左转 / 右转 / 停止

表情系统

开心 / 困困 / 生气 / 惊讶 四种表情

炫彩灯效

呼吸灯 / 彩虹灯 / 闪烁灯 / 常亮灯

组合动作

跳舞 / 打招呼 / 卖萌

控制方式

微信小程序 + 蓝牙遥控器双模式

供电方式

单节18650锂电池,移动便携


二、整体架构

桌面宠物机器人采用 "应用层(小程序、遥控)— 通信层(BT36蓝牙)— 控制层(STM32)— 执行层(舵机、OLED、LED)" 四层架构:

2.1 工作原理

  • 蓝牙连接:大夏龙雀 BT36 模块上电后自动广播,手机微信小程序或蓝牙遥控器搜索并建立 BLE 连接;

  • 指令下发:用户在小程序端点击方向键、表情按钮或灯效按钮,指令通过 BLE 透传至 BT36;

  • UART通信:BT36 通过 UART 将指令发送给 STM32F103C6T6A 主控;

  • 指令解析:STM32 解析指令格式,执行对应的舵机运动、OLED表情切换或RGB灯效变换;

  • 状态回复:执行完成后通过蓝牙回复 ACK,小程序端更新状态显示。

  • 2.2 硬件选型

    模块

    型号

    接口

    数量

    说明

    主控

    STM32F103C6T6A

    –

    ×1

    LQFP-48封装,资源充足

    蓝牙

    大夏龙雀 BT36

    UART

    ×1

    BLE5.3,主从一体,AT指令配置

    显示

    0.96" OLED

    I2C

    ×1

    128×64分辨率,SSD1306驱动

    舵机

    SG90 微型舵机

    PWM

    ×4

    180°旋转,重量轻,适合桌面级

    灯光

    RGB LED(共阴)

    PWM

    ×1

    三原色混合,实现炫彩效果

    电源

    18650 锂电池

    –

    ×1

    3.7V/2000mAh以上,续航持久

    搭建

    面包板 + 杜邦线

    –

    若干

    免焊接,快速原型验证


    三、硬件设计

    3.1 硬件连接总览

    全部电路通过面包板 + 杜邦线搭建,无需PCB,零基础也能快速上手。连接示意图如下

    3.2 引脚分配

    // STM32F103C6T6A 引脚分配

    #define SERVO_LEFT_LEG_PIN GPIO_Pin_0 // PA0 – 左腿
    #define SERVO_RIGHT_LEG_PIN GPIO_Pin_1 // PA1 – 右腿
    #define SERVO_LEFT_FOOT_PIN GPIO_Pin_2 // PA2 – 左前足
    #define SERVO_RIGHT_FOOT_PIN GPIO_Pin_3 // PA3 – 右前足

    #define OLED_SDA_PIN GPIO_Pin_7 // PB7 – I2C SDA
    #define OLED_SCL_PIN GPIO_Pin_6 // PB6 – I2C SCL

    #define BT_TX_PIN GPIO_Pin_9 // PA9 – USART1 TX
    #define BT_RX_PIN GPIO_Pin_10 // PA10 – USART1 RX

    #define LED_R_PIN GPIO_Pin_8 // PA8 – TIM1 CH1
    #define LED_G_PIN GPIO_Pin_9 // PB9 – TIM4 CH4
    #define LED_B_PIN GPIO_Pin_8 // PB8 – TIM4 CH3

    3.3 舵机驱动原理

    SG90舵机的驱动信号是20ms周期的PWM波,高电平宽度从0.5ms到2.5ms对应0°到180°:

    高电平宽度

    对应角度

    0.5ms

    0°

    1.0ms

    45°

    1.5ms

    90°(中位)

    2.0ms

    135°

    2.5ms

    180°

    通过STM32定时器PWM输出,动态调整CCR寄存器即可控制舵机角度。四只舵机分别控制两条后腿和两只前足,通过协调不同的角度组合实现前进、后退、转向等步态。

    3.4 电源方案

    单节18650锂电池(3.7V标称电压)直接为整个系统供电:

    • STM32F103C6T6A:工作电压2.0~3.6V,核心板自带的LDO即可实现MCU供电

    • SG90舵机:工作电压4.8V典型,3.7V也能工作但扭矩稍小,桌面宠物重量轻完全够用

    • BT36蓝牙模块:支持3.3~5V宽电压,3.7V直接供电

    • OLED显示屏:3.3V供电,由STM32的3.3V引脚

    我们使用的锂电池充放电方案是TP4056,直接粘贴在面包板上,方便使用Type-C接口直接对18650锂电池进行充电。


    四、机械结构设计

    桌面宠物采用4舵机方案,结构简单、动作灵活:

    4.1 四舵机布局

    • 后腿 ×2:左右各一只,负责主要的行走动力输出,摆动范围约60°

    • 前足 ×2:左右各一只,负责辅助支撑和姿态调整,使动作更自然可爱

    4.2 步态原理

    通过四只舵机的角度协调变化实现不同运动:

    前进步态:

  • 左前足抬起 → 右腿后蹬 → 身体前倾

  • 右前足抬起 → 左腿后蹬 → 身体继续前进

  • 交替循环,实现"蹒跚学步"的可爱效果

  • 转向原理:

    • 左转:右腿加速前摆,左腿减速或小幅后摆,身体向左偏转

    • 右转:左腿加速前摆,右腿减速或小幅后摆,身体向右偏转

    4.3 结构材质

    我们使用的刚好是面包板,无需任何焊接即可实现电路的快速搭建,可以用:

    建议先用简单材料验证步态,满意后再做精致外壳。


    五、OLED表情系统

    小小的OLED屏幕是宠物的"灵魂之窗",通过绘制不同表情赋予宠物性格:

    5.1 四种基础表情

    表情

    触发场景

    视觉效果

    开心

    正常待机 / 收到指令执行成功

    弯弯笑眼 + 上扬嘴角

    困困

    长时间无操作 / 夜晚模式

    眯成一条缝 + Zzz

    生气

    连续撞墙 / 被频繁打扰

    倒八字眉 + 嘴角下撇

    惊讶

    首次连接 / 收到新指令

    圆眼睛 + O型嘴

    5.2 表情绘制实现

    使用SSD1306驱动的0.96寸OLED(128×64),通过I2C通信:

    // 表情数据结构
    typedef struct {
    const uint8_t *face_data; // 表情位图数据
    uint8_t width; // 表情宽度
    uint8_t height; // 表情高度
    } Expression_t;

    // 表情枚举
    typedef enum {
    EXP_HAPPY = 0, // 开心
    EXP_SLEEPY = 1, // 困困
    EXP_ANGRY = 2, // 生气
    EXP_SURPRISE = 3 // 惊讶
    } Expression_Type;

    // 切换表情函数
    void OLED_ShowExpression(Expression_Type exp)
    {
    // 清屏
    OLED_Clear();

    // 在屏幕中央绘制表情
    uint8_t x = (128 – expressions[exp].width) / 2;
    uint8_t y = (64 – expressions[exp].height) / 2;

    OLED_DrawBMP(x, y, expressions[exp].width, expressions[exp].height,
    expressions[exp].face_data);

    // 可附加装饰:脸颊红晕等
    if(exp == EXP_HAPPY) {
    OLED_DrawCircle(30, 40, 5, 1); // 左脸颊
    OLED_DrawCircle(98, 40, 5, 1); // 右脸颊
    }

    OLED_Refresh();
    }

    表情图案可以用 LCD Image Converter 或类似工具将图片转换为C数组,直接嵌入代码中。


    六、RGB炫彩灯效

    RGB LED是宠物的"氛围担当",四种灯效模式随心切换:

    6.1 四种灯效模式

    模式

    效果描述

    适用场景

    呼吸灯

    PWM渐变亮灭,温柔如呼吸

    待机状态,安静优雅

    彩虹灯

    RGB三色循环渐变,炫彩夺目

    跳舞时,活泼热闹

    闪烁灯

    快速闪烁,活泼俏皮

    开心/惊讶时

    常亮灯

    稳定单色光,柔和护眼

    夜灯模式,温暖陪伴

    6.2 PWM混色原理

    三路独立PWM,每路8位分辨率(0~255),可混合出约1677万种颜色:

    // RGB颜色设置函数
    void RGB_SetColor(uint8_t r, uint8_t g, uint8_t b)
    {
    // 直接修改CCR寄存器,0~255映射到0~ARR
    TIM_SetCompare1(TIM1, r); // R通道
    TIM_SetCompare3(TIM4, g); // G通道
    TIM_SetCompare4(TIM4, b); // B通道
    }

    // 呼吸灯效果
    void LED_Breathing_Effect(void)
    {
    static uint8_t brightness = 0;
    static uint8_t direction = 1;

    if(direction) {
    brightness++;
    if(brightness >= 200) direction = 0;
    } else {
    brightness–;
    if(brightness == 0) direction = 1;
    }

    RGB_SetColor(brightness, brightness / 2, 0); // 暖橙色呼吸
    }


    七、蓝牙通信协议

    通信核心是深圳大夏龙雀科技 BT36 蓝牙模块,这是整个项目的无线桥梁。

    7.1 BT36 模块特性

    BT36 是大夏龙雀出品的高性价比 BLE 5.3 模块,采用 DIALOG DA14535 芯片,主从一体设计。在本项目中,它的优势体现在:

    • BLE 5.3 协议:连接速度快、功耗低、抗干扰能力强

    • 主从一体:既可作从机被手机连接,也可作主机连接遥控器

    • AT指令丰富:支持修改设备名、波特率、UUID、发射功率等参数,响应迅速(<10ms)

    • 宽电压工作:3.3V~5V,直接接锂电池,无需额外电平转换

    • UART透传:透明传输模式,开发简单,像操作串口一样使用蓝牙

    • 通信距离远:空旷环境下可达数十米,桌面场景绰绰有余

    在实际开发中,BT36的稳定性令人印象深刻——电机PWM信号产生的电磁干扰对蓝牙通信几乎没有影响,连接稳定不掉线,这对于面包板搭建的原型项目来说非常关键。

    7.2 通信协议设计

    采用简洁易解析的文本指令协议,便于调试和扩展:

    7.3 串口解析实现

    // 蓝牙数据接收缓冲区
    #define BT_RX_BUF_SIZE 64
    uint8_t bt_rx_buf[BT_RX_BUF_SIZE];
    uint8_t bt_rx_index = 0;

    // USART1 中断接收(BT36连接)
    void USART1_IRQHandler(void)
    {
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
    uint8_t ch = USART_ReceiveData(USART1);

    if(ch == '\\n' || bt_rx_index >= BT_RX_BUF_SIZE – 1) {
    bt_rx_buf[bt_rx_index] = '\\0';
    // 完整指令,解析处理
    BT_Parse_Command((char*)bt_rx_buf);
    bt_rx_index = 0;
    } else if(ch != '\\r') {
    bt_rx_buf[bt_rx_index++] = ch;
    }
    }
    }

    // 指令解析函数
    void BT_Parse_Command(char *cmd)
    {
    if(strncmp(cmd, "FWD", 3) == 0) {
    Servo_WalkForward();
    OLED_ShowExpression(EXP_HAPPY);
    BT_SendString("OK\\r\\n");
    }
    else if(strncmp(cmd, "BACK", 4) == 0) {
    Servo_WalkBackward();
    BT_SendString("OK\\r\\n");
    }
    else if(strncmp(cmd, "LEFT", 4) == 0) {
    Servo_TurnLeft();
    BT_SendString("OK\\r\\n");
    }
    else if(strncmp(cmd, "RIGHT", 5) == 0) {
    Servo_TurnRight();
    BT_SendString("OK\\r\\n");
    }
    else if(strncmp(cmd, "STOP", 4) == 0) {
    Servo_Stop();
    BT_SendString("OK\\r\\n");
    }
    else if(strncmp(cmd, "EXP:", 4) == 0) {
    uint8_t exp_num = cmd[4] – '0';
    if(exp_num <= 3) {
    OLED_ShowExpression(exp_num);
    BT_SendString("OK\\r\\n");
    }
    }
    else if(strncmp(cmd, "LED:", 4) == 0) {
    uint8_t led_num = cmd[4] – '0';
    if(led_num <= 3) {
    LED_SetMode(led_num);
    BT_SendString("OK\\r\\n");
    }
    }
    else if(strncmp(cmd, "ACT:", 4) == 0) {
    Action_Execute(cmd + 4);
    BT_SendString("OK\\r\\n");
    }
    else {
    BT_SendString("ERR\\r\\n");
    }
    }


    八、系统控制流程

    8.1 主循环结构

    int main(void)
    {
    // 系统初始化
    SystemInit();
    Servo_Init(); // 舵机PWM初始化
    OLED_Init(); // OLED初始化
    RGB_Init(); // RGB灯PWM初始化
    USART1_Init(9600); // 蓝牙串口初始化(BT36默认9600)

    // 开机动画
    OLED_ShowExpression(EXP_HAPPY);
    LED_SetMode(LED_BREATHING);
    Servo_WaveHello(); // 开机打招呼

    while(1)
    {
    // 检查是否收到蓝牙指令
    if(bt_cmd_ready) {
    BT_Parse_Command(bt_cmd_buffer);
    bt_cmd_ready = 0;
    }

    // LED灯效任务
    LED_Task_Handler();

    // 待机检测
    if(HAL_GetTick() – last_cmd_time > 10000) {
    if(current_expression != EXP_SLEEPY) {
    OLED_ShowExpression(EXP_SLEEPY);
    LED_SetMode(LED_BREATHING); // 柔和呼吸
    }
    }
    }
    }

    8.2 组合动作实现

    组合动作是让宠物"活起来"的关键,通过编排一系列舵机角度序列实现:

    // 跳舞动作序列
    void Action_Dance(void)
    {
    OLED_ShowExpression(EXP_HAPPY);
    LED_SetMode(LED_RAINBOW); // 彩虹灯效

    // 左右摇摆 + 前足摆动
    for(int i = 0; i < 4; i++) {
    Servo_SetAngle(SERVO_LEFT_LEG, 60 + i * 15);
    Servo_SetAngle(SERVO_RIGHT_LEG, 120 – i * 15);
    Delay_Ms(200);
    }
    for(int i = 0; i < 4; i++) {
    Servo_SetAngle(SERVO_LEFT_LEG, 120 – i * 15);
    Servo_SetAngle(SERVO_RIGHT_LEG, 60 + i * 15);
    Delay_Ms(200);
    }

    // 前足上下摆动
    for(int i = 0; i < 3; i++) {
    Servo_SetAngle(SERVO_LEFT_FOOT, 45);
    Servo_SetAngle(SERVO_RIGHT_FOOT, 45);
    Delay_Ms(150);
    Servo_SetAngle(SERVO_LEFT_FOOT, 135);
    Servo_SetAngle(SERVO_RIGHT_FOOT, 135);
    Delay_Ms(150);
    }

    Servo_Stop();
    LED_SetMode(LED_BREATHING);
    }

    // 打招呼动作
    void Action_Hello(void)
    {
    OLED_ShowExpression(EXP_HAPPY);

    // 右前足抬起挥动
    for(int i = 0; i < 3; i++) {
    Servo_SetAngle(SERVO_RIGHT_FOOT, 30);
    Delay_Ms(200);
    Servo_SetAngle(SERVO_RIGHT_FOOT, 60);
    Delay_Ms(200);
    }

    Servo_Stop();
    }


    九、微信小程序控制端

    为了让宠物的控制更便捷、作品更完整,开发了配套的微信小程序控制端,通过 BLE 直接连接 BT36 模块:

    9.1 小程序功能架构

    小程序包含三个主要页面:

    页面

    功能

    控制页

    方向控制 + 表情切换 + 灯效选择 + 快捷动作

    设置页

    舵机角度微调、响应速度设置、自动休眠时间

    关于页

    作品介绍、版本信息、教程链接

    9.2 BLE连接核心代码

    // 小程序端 – 蓝牙连接与控制
    const DEVICE_NAME = 'DX-BT36'; // BT36默认设备名
    const SERVICE_UUID = '0000FFE0-0000-1000-8000-00805F9B34FB';
    const CHAR_UUID = '0000FFE1-0000-1000-8000-00805F9B34FB';

    let deviceId = null;
    let connected = false;

    // 搜索并连接设备
    function connectDevice() {
    wx.startBluetoothDevicesDiscovery({
    services: [SERVICE_UUID],
    success: (res) => {
    console.log('开始搜索设备');

    wx.onBluetoothDeviceFound((devices) => {
    const device = devices.devices.find(d =>
    d.name === DEVICE_NAME || d.localName === DEVICE_NAME
    );
    if(device) {
    wx.stopBluetoothDevicesDiscovery();
    createConnection(device.deviceId);
    }
    });
    }
    });
    }

    // 建立连接
    function createConnection(id) {
    wx.createBLEConnection({
    deviceId: id,
    success: () => {
    deviceId = id;
    connected = true;
    wx.showToast({ title: '连接成功', icon: 'success' });

    // 监听特征值变化
    wx.notifyBLECharacteristicValueChange({
    deviceId,
    serviceId: SERVICE_UUID,
    characteristicId: CHAR_UUID,
    success: () => {
    wx.onBLECharacteristicValueChange((res) => {
    const data = ab2str(res.value);
    console.log('收到:', data);
    });
    }
    });
    }
    });
    }

    // 发送指令
    function sendCommand(cmd) {
    if(!connected) {
    wx.showToast({ title: '请先连接设备', icon: 'none' });
    return;
    }

    const buffer = str2ab(cmd + '\\r\\n');
    wx.writeBLECharacteristicValue({
    deviceId,
    serviceId: SERVICE_UUID,
    characteristicId: CHAR_UUID,
    value: buffer,
    success: () => console.log('发送:', cmd)
    });
    }

    // 工具函数:字符串转ArrayBuffer
    function str2ab(str) {
    const buffer = new ArrayBuffer(str.length);
    const view = new Uint8Array(buffer);
    for(let i = 0; i < str.length; i++) {
    view[i] = str.charCodeAt(i);
    }
    return buffer;
    }

    function ab2str(buffer) {
    return String.fromCharCode.apply(null, new Uint8Array(buffer));
    }

    // 方向控制按钮
    const control = {
    forward: () => sendCommand('FWD'),
    backward: () => sendCommand('BACK'),
    turnLeft: () => sendCommand('LEFT'),
    turnRight: () => sendCommand('RIGHT'),
    stop: () => sendCommand('STOP'),
    };

    // 表情切换
    const expressions = {
    happy: () => sendCommand('EXP:0'),
    sleepy: () => sendCommand('EXP:1'),
    angry: () => sendCommand('EXP:2'),
    surprise: () => sendCommand('EXP:3'),
    };

    // 灯效切换
    const ledModes = {
    breathing: () => sendCommand('LED:0'),
    rainbow: () => sendCommand('LED:1'),
    blink: () => sendCommand('LED:2'),
    solid: () => sendCommand('LED:3'),
    };

    // 快捷动作
    const actions = {
    dance: () => sendCommand('ACT:DANCE'),
    hello: () => sendCommand('ACT:HELLO'),
    cute: () => sendCommand('ACT:CUTE'),
    };

    9.3 小程序界面设计要点

    • 方向控制区:D-pad方向键布局,中间键为停止,符合游戏手柄使用习惯

    • 表情切换区:4个表情按钮横向排列,点击即切换,状态反馈清晰

    • 灯效选择区:4种灯效彩色按钮,视觉上即传达灯光氛围

    • 快捷动作区:跳舞/打招呼/卖萌三个大按钮,一键触发组合动作

    • 状态栏:顶部实时显示连接状态,已连接显示绿色圆点


    十、项目总结

    这款桌面宠物机器人虽然只用面包板搭建,但麻雀虽小五脏俱全,从硬件到软件实现了完整的全栈设计:

    10.1 项目亮点

    • 全栈自主设计:从电路搭建、嵌入式程序到微信小程序,端到端完整实现,技术覆盖面广

    • BT36深度适配:充分发挥大夏龙雀 BT36 蓝牙模块的性能优势,BLE5.3稳定连接、AT指令灵活配置、宽电压适配

    • 面包板入门友好:无需PCB、无需焊接,所有耗材易购,降低了复刻门槛,适合教学和推广

    • 趣味性与传播性:可爱的表情、灵动的动作、微信小程序控制,天然适合短视频和社交分享

    • 扩展性强:可以不断添加新表情、新动作、新传感器(触摸/声音/光线),持续迭代

    10.2 成本清单

    物料

    单价(参考)

    数量

    小计

    STM32F103C6T6A 最小系统板

    约15元

    ×1

    15元

    大夏龙雀 BT36 蓝牙模块

    约20元

    ×1

    20元

    SG90 微型舵机

    约5元

    ×4

    20元

    0.96" OLED 显示屏

    约8元

    ×1

    8元

    RGB LED + 电阻

    约1元

    ×1

    1元

    18650 锂电池 + 电池盒

    约10元

    ×1

    10元

    面包板 + 杜邦线

    约10元

    若干

    10元

    总计

    –

    –

    约84元

    赞(0)
    未经允许不得转载:171主机测评 » 桌面宠物机器人全栈设计
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址