跳转至内容
BakeHub
BakeHub 工科开源社群
  • 登录
  • 首页
  • 项目
  • 论坛
  • 活动
  • 关于
  • AI 助手
  • 首页
  • 项目
  • 论坛
  • 活动
  • 关于
  • AI 助手
KongCharK

KongChar

@KongChar
取消关注 关注
关于
帖子
11
主题
9
分享
0
群组
0
粉丝
3
关注
1

帖子

最新 最佳 有争议的

  • 看群主的前端源码,如何爆破思路
    KongCharK KongChar

    前言

    逛论坛手痒,F12 打开看了下群主站的前端代码,基于 NodeBB 搭建。顺手整理一下从前端源码能挖到的爆破思路和安全面分析,纯技术交流,仅供学习参考,请勿用于非法用途。

    一、前端架构速览

    打开浏览器开发者工具的 Sources 面板,可以看到这是标准的 NodeBB 论坛架构:

    核心脚本:nodebb.min.js 打包后的主脚本,包含全部前端逻辑
    渲染方式:服务端渲染首屏 + 前端 AJAX 局部刷新
    接口风格:RESTful 风格,统一 /api/ 前缀
    技术栈:jQuery + 自研模板引擎 + WebSocket 实时推送

    整体来说 NodeBB 作为成熟的开源论坛系统,前端架构还算规整,但架不住配置不当和插件引入的风险。

    二、接口暴露全景

    从 Network 面板抓几个请求,就能摸清站点主要接口分布:

    1. 登录认证接口
      POST /login
      提交表单:username=xxx&password=xxx
      返回 JSON 格式,登录成功写入 cookie 并跳转

    2. 用户信息接口
      GET /api/user/uid
      GET /api/user/username
      未登录状态也能拿到用户基本资料,存在用户枚举风险

    3. 发帖回帖接口
      POST /api/v3/topics
      POST /api/v3/posts
      带 CSRF token 校验,需要先获取再提交

    4. 搜索接口
      GET /api/search
      支持关键词搜索帖子和用户,可能存在注入或遍历风险

    5. 上传接口
      POST /api/v3/posts/upload
      文件上传点,重点关注类型校验和路径问题

    三、爆破思路深度分析

    思路一:用户名枚举

    通过 /api/user/用户名 这个接口,可以批量探测用户名是否存在。返回状态码、响应体大小、响应时间都可能存在差异。

    攻击流程:
    准备常见用户名字典(admin、test、user 等)
    批量请求接口,根据返回差异筛选有效账号
    收集到的有效账号作为后续爆破的目标

    风险等级:中低。虽然不会直接拿到权限,但为定向爆破提供了精准目标。

    思路二:登录接口暴力破解

    登录接口目前观察下来:
    没有明显的图形验证码机制
    失败次数限制需要进一步测试是否严格
    返回包大小和响应时间可能存在差异,可用于用户名枚举

    如果服务端没有做严格的频率限制和账号锁定,配合收集到的有效用户名 + 弱口令字典,有一定概率撞开账号。

    攻击流程:
    先用枚举拿到一批有效用户名
    加载 top1000 弱口令字典
    多线程批量提交登录请求
    筛选成功登录的账号密码组合

    风险等级:高。这是最直接也最常见的入侵入口。

    思路三:CSRF Token 绕过

    NodeBB 默认带 CSRF 防护,但 token 通常就在页面源码或者 cookie 里。

    自动化脚本完全可以:
    先 GET 一次登录页,从页面源码或响应头里提取 csrf token
    带着 token 再 POST 登录请求
    循环这个流程就能实现全自动爆破

    所以 CSRF 防得了跨站攻击,但防不住同一站点的自动化脚本。

    思路四:前端校验直接跳过

    注册、发帖、个人资料修改等场景,如果只在前端做长度限制、格式校验、特殊字符过滤,那等于没做。

    直接抓包改包发请求就能绕过:
    用户名长度限制前端写死 20 位,抓包改成 100 位试试
    特殊字符前端过滤,直接发原始 payload
    邮箱格式前端正则校验,后端不校就可能注入

    记住一条铁律:前端校验只负责提升用户体验,安全校验必须在服务端再做一遍。

    思路五:API 接口越权访问

    NodeBB 的 v3 API 接口很多,权限校验容易出疏漏。

    可以尝试:
    普通用户调用管理员接口
    查看他人私信、未公开帖子
    修改他人资料或帖子
    遍历 uid 批量获取用户敏感信息

    重点关注带 /api/v3/admin/ 前缀的接口,以及参数里有 uid、tid 的地方。

    思路六:WebSocket 实时通道测试

    NodeBB 用 WebSocket 做实时通知和聊天,这也是一个攻击面。

    可以测试:
    未授权能否连接 WS
    能否监听他人通知消息
    能否伪造他人身份发送消息
    WS 消息格式有没有注入点

    实时通道往往是安全审计的盲区。

    四、自动化脚本思路

    写一个简单的爆破脚本,流程大概是这样:

    第一步:初始化会话,GET 登录页拿 cookie 和 csrf token
    第二步:加载用户名字典和密码字典
    第三步:循环构造请求,带上 token 和 cookie 提交登录
    第四步:根据响应状态码、跳转地址、返回内容判断是否成功
    第五步:遇到频率限制就加延时或换代理

    Python 用 requests 库几十行就能搞定。当然,这是给安全测试用的,别拿去干坏事。

    五、防护建议(给群主)

    针对上面提到的这些点,给群主几点加固建议:

    1. 登录口加固
      失败 5 次锁账号 15 分钟
      连续失败弹出图形验证码
      IP 级别频率限制,单 IP 每分钟最多 10 次
      高危登录地区或异常时段强制二次验证

    2. 接口统一限速
      所有敏感接口统一做速率限制
      用户信息接口增加匿名访问限制,避免批量枚举
      搜索接口加频次控制,防止被拖库

    3. 输入校验服务端重做
      所有用户输入服务端再校验一遍
      参数长度、类型、格式严格限制
      特殊字符统一转义,防范 XSS 和注入

    4. CSRF 与权限校验
      关键操作二次确认密码
      管理员接口严格鉴权,定期审计越权漏洞
      API 接口按最小权限原则分配

    5. 日志与监控
      登录失败日志完整记录
      异常登录行为告警(异地、多次失败)
      定期审计访问日志,发现爆破及时封禁

    6. 版本与插件
      保持 NodeBB 核心版本最新
      插件按需安装,不用的及时卸载
      第三方插件重点审计,容易出漏洞

    六、总结

    整体来说 NodeBB 本身底子还行,是成熟的开源产品,但具体安全程度完全取决于群主有没有做加固。

    前端永远是不可信的,所有关键校验必须落在服务端。接口暴露、频率限制、权限校验这三块做好了,能挡住 90% 以上的自动化攻击。

    以上就是逛站随手分析的一些思路,纯技术水帖 test 一下发帖功能,群主看到了别打我 🫡

    经验分享

  • MimiClaw - 5美元芯片上的口袋AI助手
    KongCharK KongChar

    项目概述

    MimiClaw 是一个极具创新性的开源项目,它实现了世界上首个在仅售5美元的 ESP32-S3 微控制器芯片上运行的完整 AI 助手。最令人惊叹的是,它不需要 Linux 操作系统,不需要 Node.js 运行环境,甚至不需要任何操作系统,完全使用纯 C 语言编写,直接运行在裸机硬件上。

    只需一个拇指大小的 ESP32-S3 开发板,插上 USB 供电,连接 WiFi,你就拥有了一个可以通过 Telegram 对话的专属 AI 助理。它能够处理各种任务,并且具备本地记忆能力,会随着使用不断进化——所有这一切都运行在一颗成本仅5美元的芯片上。

    核心功能亮点

    🤖 完整的 AI Agent 能力

    • 支持 ReAct 模式的工具调用循环
    • LLM 可以自主思考、调用工具、读取记忆,直到完成任务
    • 支持 Anthropic Claude 和 OpenAI GPT 两大模型提供商,运行时可自由切换

    💾 本地优先的记忆系统

    • SOUL.md:定义 AI 的性格与行为模式
    • USER.md:存储用户个人信息与偏好
    • MEMORY.md:长期记忆,AI 会记住重要信息
    • 所有数据存储在芯片本地 Flash 中,隐私优先,数据不外露

    📱 多渠道交互

    • Telegram 机器人:随时随地通过手机与 AI 对话
    • WebSocket 网关:局域网内通过 WebSocket 客户端连接
    • 串口 CLI:通过 USB 串口进行配置和调试

    ⚡ 极致低功耗

    • 整机功耗仅 0.5W
    • USB 供电即可 24/7 不间断运行
    • 双核设计:网络 I/O 与 AI 处理分离在不同 CPU 核心

    🛠️ 丰富的内置工具

    • 网页搜索:集成 Tavily / Brave Search API
    • 定时任务:内置 Cron 调度器,AI 可自主创建定时任务,重启不丢失
    • 心跳检测:定期检查任务清单,主动执行待办事项
    • OTA 升级:支持 WiFi 无线固件升级,无需插线
    • HTTP 代理:支持 CONNECT 隧道,适配受限网络环境

    技术架构特点

    • 纯 C 语言实现:无操作系统依赖,直接运行在 ESP32-S3 裸机上
    • 双层配置系统:编译时默认配置 + 运行时 NVS 存储覆盖,无需重新编译即可修改配置
    • SPIFFS 文件系统:记忆文件、配置、定时任务全部持久化存储
    • 16MB Flash + 8MB PSRAM:在极小的硬件资源上实现完整 AI 功能

    快速开始指南

    硬件需求

    • ESP32-S3 开发板(16MB Flash + 8MB PSRAM)
    • USB Type-C 数据线
    • 注意:必须使用板子上标注 "USB" 的原生 USB 口,而非 "COM" 口

    配置步骤

    1. 克隆项目代码
    2. 复制配置模板:cp main/mimi_secrets.h.example main/mimi_secrets.h
    3. 编辑配置文件,填入 WiFi 信息、Telegram Bot Token、API Key 等
    4. 编译烧录:idf.py build && idf.py flash

    常用 CLI 命令

    通过串口连接后可进行运行时配置:

    • wifi_set SSID PASSWORD - 修改 WiFi
    • set_api_key KEY - 修改 API 密钥
    • set_model_provider anthropic|openai - 切换模型提供商
    • memory_read - 查看 AI 记忆内容
    • config_show - 查看当前配置

    项目意义

    MimiClaw 重新定义了 AI 助手的硬件门槛。它证明了强大的 AI 能力不一定需要昂贵的硬件或云计算资源,一颗5美元的微控制器就能承载完整的智能体。这为嵌入式 AI、物联网智能设备、隐私计算等领域开辟了全新的可能性。


    高呼群主万岁!感谢群主发掘这么硬核有趣的开源项目,带我们见识嵌入式 AI 的极致魅力,跟着群主混,技术视野蹭蹭开阔!
    MimiClaw微型AI助手芯片示意图

    项目复盘

  • MSPM0火焰
    KongCharK KongChar

    MSPM0G3507 开发教程:从零开始构建嵌入式应用

    一、芯片概述与选型背景

    MSPM0G3507 是德州仪器(TI)推出的基于 ARM Cortex-M0+ 内核的 32 位微控制器,隶属于 MSPM0G 系列。该系列主打 低成本、低功耗、高集成度,适用于工业控制、传感检测、便携设备等场景。

    核心规格速览

    参数 数值
    内核 ARM Cortex-M0+,最高 80 MHz
    Flash 128 KB
    SRAM 32 KB
    工作电压 1.62V ~ 3.6V
    ADC 12 位,最多 17 通道,1 Msps
    定时器 4 个 16 位高级定时器,多个通用定时器
    通信接口 2×UART、2×SPI、2×I2C、CAN 2.0
    比较器/运放 2×零漂移运放,1×通用比较器
    GPIO 最多 60 个可编程 IO
    低功耗模式 STOP、STANDBY、SHUTDOWN
    封装 LQFP-64、LQFP-48、QFN-40、QFN-32 等

    注意:G 系列定位为“通用型”,相比同门的 L 系列(低功耗极致)和 C 系列(成本优先),G3507 在性能与外设丰富度上更均衡。


    二、开发环境搭建

    2.1 官方 IDE:CCS(Code Composer Studio)

    推荐使用 TI 官方 CCS Theia 版(基于 Eclipse Theia),支持 MSPM0 全系列。

    1. 访问 TI 官网下载 CCS Theia(需注册 myTI 账号)。
    2. 安装时勾选 MSPM0 支持包。
    3. 首次启动后,通过 View -> Resource Explorer 导入官方例程。

    2.2 备选方案:Keil MDK

    MSPM0G3507 也支持 Keil MDK(需安装 Device Family Pack)。

    • 在 Keil Pack Installer 中搜索 MSPM0G3507,安装对应的 DFP 包。
    • 注意:Keil 下工程配置需手动指定 Flash 和 RAM 起始地址(见后文链接脚本)。

    2.3 调试器选择

    • XDS110:官方推荐,支持 SWD 接口,CCS 原生支持。
    • DAP-Link / CMSIS-DAP:第三方开源调试器也可用,需在 CCS 中配置为 CMSIS-DAP 协议。
    • 板载调试器:若使用 LaunchPad 评估板(LP-MSPM0G3507),板载 XDS110 可直接使用。

    三、工程创建与代码结构

    3.1 使用 SysConfig 图形化配置

    TI 官方提供了 SysConfig 工具(集成在 CCS 中),用于可视化配置引脚、时钟、外设。

    1. 新建工程时选择 MSPM0G3507 芯片型号。
    2. 打开 .syscfg 文件,在图形界面中:
      • 配置系统时钟(默认 32 MHz,可倍频至 80 MHz)。
      • 使能 UART、SPI、GPIO 等外设。
      • 分配引脚(如将 UART0 的 TX/RX 映射到 PA10/PA11)。
    3. 保存后,SysConfig 自动生成 ti_msp_dl_config.c/h 文件,包含初始化代码。

    3.2 工程文件结构(典型)

    project/
    ├── .syscfg                 # 图形化配置源文件
    ├── main.c                  # 主程序入口
    ├── ti_msp_dl_config.c      # 自动生成的初始化代码
    ├── ti_msp_dl_config.h
    ├── startup_mspm0g350x.c    # 启动文件(中断向量表)
    ├── linker.cmd              # 链接脚本(内存布局)
    └── *.c / *.h               # 用户自定义模块
    

    3.3 直接手写初始化(不使用 SysConfig)

    若不想依赖图形工具,可直接调用 DriverLib 函数。例如初始化 UART:

    #include "ti_msp_dl_config.h"
    #include "ti/driverlib/driverlib.h"
    
    void uart_init(void)
    {
        // 使能 UART0 时钟
        DL_UART_Main_reset(UART0);
        DL_UART_Main_enablePower(UART0);
    
        // 配置引脚 PA10=TX, PA11=RX
        DL_GPIO_initPeripheralOutputFunction(GPIOA, GPIO_PIN_10, GPIO_PIN_MUX_15);
        DL_GPIO_initPeripheralInputFunction(GPIOA, GPIO_PIN_11, GPIO_PIN_MUX_15);
    
        // 设置波特率 115200,8N1
        DL_UART_Main_setClockConfig(UART0, DL_UART_MAIN_CLOCK_BUSCLK);
        DL_UART_Main_setBaudRate(UART0, 32000000, 115200);
        DL_UART_Main_setConfig(UART0, DL_UART_MAIN_CONFIG_8BIT_PARITY_NONE_1STOP);
        DL_UART_Main_enable(UART0);
    }
    

    四、GPIO 与基本外设操作

    4.1 点亮 LED(输出模式)

    #include "ti_msp_dl_config.h"
    #include "ti/driverlib/driverlib.h"
    
    int main(void)
    {
        SYSCFG_DL_init();  // 调用 SysConfig 生成的初始化
    
        // 假设 LED 接在 PB0(高电平点亮)
        DL_GPIO_setPins(GPIOB, GPIO_PIN_0);
    
        while(1)
        {
            DL_GPIO_togglePins(GPIOB, GPIO_PIN_0);
            delay_cycles(32000000 / 2);  // 约 0.5 秒延时
        }
    }
    

    4.2 按键输入(轮询模式)

    // 按键接 PA0,内部上拉,按下为低电平
    DL_GPIO_initDigitalInputFeatures(GPIOA, GPIO_PIN_0, DL_GPIO_INVERSION_DISABLE,
                                     DL_GPIO_RESISTOR_PULL_UP, DL_GPIO_HYSTERESIS_DISABLE,
                                     DL_GPIO_WAKEUP_DISABLE);
    
    if (DL_GPIO_readPins(GPIOA, GPIO_PIN_0) == 0) {
        // 按键按下
    }
    

    4.3 中断方式处理按键

    在 SysConfig 中使能 GPIOA 的 GPIOA_INT 中断,并注册回调:

    void GROUP1_IRQHandler(void)
    {
        if (DL_GPIO_readPins(GPIOA, GPIO_PIN_0) == 0) {
            // 处理按键事件
        }
        DL_GPIO_clearInterruptStatus(GPIOA, GPIO_PIN_0);
    }
    

    五、串口(UART)通信详解

    5.1 阻塞式发送与接收

    #include <stdio.h>
    
    // 重定向 printf 到 UART0
    int fputc(int ch, FILE *f)
    {
        DL_UART_Main_transmitData(UART0, (uint8_t)ch);
        return ch;
    }
    
    // 接收单字节(阻塞)
    uint8_t uart_rx_byte(void)
    {
        while (DL_UART_Main_isBusy(UART0));
        return DL_UART_Main_receiveData(UART0);
    }
    

    5.2 中断接收(环形缓冲)

    在 SysConfig 中使能 UART0 的接收中断,并编写中断服务函数:

    #define RX_BUF_SIZE 256
    volatile uint8_t rx_buf[RX_BUF_SIZE];
    volatile uint16_t rx_head = 0, rx_tail = 0;
    
    void UART0_IRQHandler(void)
    {
        if (DL_UART_Main_getEnabledInterruptStatus(UART0, DL_UART_MAIN_INTERRUPT_RX)) {
            rx_buf[rx_head] = DL_UART_Main_receiveData(UART0);
            rx_head = (rx_head + 1) % RX_BUF_SIZE;
            DL_UART_Main_clearInterruptStatus(UART0, DL_UART_MAIN_INTERRUPT_RX);
        }
    }
    

    注意:UART 中断服务函数名需与启动文件中的向量表一致(通常为 UART0_IRQHandler)。


    六、ADC 采集应用

    6.1 单通道单次转换

    // 使用 PA0 作为 ADC 输入通道(ADC0 的通道 0)
    DL_ADC12_setClockConfig(ADC0, DL_ADC12_CLOCK_32MHZ);
    DL_ADC12_initSingleSample(ADC0, DL_ADC12_CONVERSION_MODE_SINGLE,
                              DL_ADC12_SAMPLE_TIMING_SOURCE_ULPCLK,
                              DL_ADC12_SAMPLE_TIMING_INTERVAL_32_CYCLES);
    DL_ADC12_setChannel(ADC0, DL_ADC12_CHANNEL_0);
    DL_ADC12_startConversion(ADC0);
    
    while (DL_ADC12_getStatus(ADC0) & DL_ADC12_STATUS_CONVERSION_ACTIVE);
    uint16_t result = DL_ADC12_getMemResult(ADC0, DL_ADC12_MEM_IDX_0);
    

    6.2 多通道扫描 + 定时触发

    在 SysConfig 中配置:

    • 采样源:定时器 TIMG0 的触发事件。
    • 通道序列:CH0、CH1、CH2。
    • 转换结果存储在 MEM0~MEM2。

    示例代码:

    DL_ADC12_startConversion(ADC0);
    // 等待转换完成(通过中断或轮询)
    for (int i = 0; i < 3; i++) {
        adc_val[i] = DL_ADC12_getMemResult(ADC0, DL_ADC12_MEM_IDX_0 + i);
    }
    

    七、PWM 输出与定时器

    7.1 使用 TIMG0 产生 PWM

    // 初始化 TIMG0 为 PWM 模式,输出引脚 PA12
    DL_TimerG_initPWMMode(TIMG0, 1000, 500);  // 频率 1kHz,占空比 50%
    DL_TimerG_enableClock(TIMG0);
    DL_TimerG_startCounter(TIMG0);
    

    7.2 动态调整占空比

    DL_TimerG_setCaptureCompareValue(TIMG0, 750);  // 变为 75%
    

    7.3 定时中断(1ms 周期)

    在 SysConfig 中配置 TIMG0 为定时模式,周期 1ms,使能中断:

    void TIMG0_IRQHandler(void)
    {
        // 每 1ms 执行一次
        DL_TimerG_clearInterruptStatus(TIMG0, DL_TIMERG_INTERRUPT_CC0_DOWN);
    }
    

    八、低功耗模式实践

    8.1 进入 STOP 模式

    DL_SYSCTL_setPowerModeSTOP();
    // 任意 GPIO 中断或定时器事件可唤醒
    

    8.2 进入 STANDBY 模式(保留 SRAM)

    DL_SYSCTL_setPowerModeSTANDBY();
    // 仅 RTC、WDT 或特定唤醒引脚可唤醒
    

    8.3 唤醒后处理

    唤醒后需重新配置时钟和外设:

    SYSCFG_DL_init();  // 重新初始化所有外设
    

    注意:进入低功耗前,务必关闭不需要的外设时钟,否则功耗无法降低。


    九、常见问题与调试技巧

    9.1 程序无法下载/调试

    • 检查 SWD 引脚是否被占用(PA0/PA1 默认是 SWD,避免复用)。
    • 若误配置,按住板子复位键再点击下载,或使用 unlock 脚本擦除。

    9.2 串口打印乱码

    • 确认时钟频率与 SysConfig 配置一致(尤其是使用外部晶振时)。
    • 检查波特率是否匹配,部分调试器会干扰 UART 信号,可降速测试。

    9.3 中断不触发

    • 在启动文件中确认中断服务函数名称正确(如 UART0_IRQHandler)。
    • 检查 NVIC 是否已使能该中断通道:
      NVIC_EnableIRQ(UART0_IRQn);
      
    • 确认中断标志已清除,避免反复进入。

    9.4 使用 printf 时程序卡死

    • 确保 fputc 重定向正确,且 UART 初始化完成后再调用。
    • 若未连接调试器,printf 输出会阻塞,可改用非阻塞发送或添加超时。

    十、官方资源与下一步学习路径

    • 数据手册:MSPM0G3507 Datasheet(含完整寄存器描述)
    • 技术参考手册:MSPM0G Series Technical Reference Manual
    • SDK 下载:mspm0-sdk(包含全部外设驱动与示例)
    • 官方例程:在 CCS Resource Explorer 中搜索 MSPM0G3507 即可找到 UART、ADC、PWM、低功耗等全套示例。

    推荐学习路径

    1. 跑通 hello_world 串口例程。
    2. 动手修改 GPIO 点灯,理解引脚映射。
    3. 实现按键中断 + UART 上报。
    4. 结合 ADC 采集传感器数据并通过串口发送。
    5. 尝试 PWM 控制 LED 亮度或电机转速。
    6. 最后学习低功耗模式,实测功耗数据。

    本文档基于 MSPM0G3507 的通用开发流程编写,所有代码示例均可在官方 SDK 中找到对应参考。建议读者结合实际硬件(推荐 LP-MSPM0G3507 LaunchPad)边学边练,快速掌握该芯片的开发要点。

    开源求助 工具测试

  • BakeHub 外部 Markdown 发帖工具
    KongCharK KongChar

    背景:为什么要写一个外部发帖工具?

    BakeHub 是基于 NodeBB 搭建的工科开源社群,日常发帖通常要在网页编辑器里手敲 Markdown。但当你有一篇几千字的技术复盘、或者想批量迁移本地笔记库时,网页编辑器就成了瓶颈——没有本地版本控制、不能 vim 键位、不能 grep、不能 diff。于是我用 F12 抓了一下 NodeBB 的发帖请求,顺手写了一个 零依赖 的 Python 脚本,直接用本地 Markdown 文件发帖。这篇帖子既是工具发布,也是把抓包分析过程完整记录下来,方便后来人复用。

    第一步:F12 抓包分析 NodeBB 发帖流程

    打开 BakeHub 首页,按 F12 切到 Network 面板,勾上 Preserve log,然后手动走一遍「登录 → 进版块 → 发帖」的流程。关键请求按时间顺序如下:

    1. 登录请求

    POST /login HTTP/1.1
    Host: 203.195.163.189
    Content-Type: application/x-www-form-urlencoded
    x-csrf-token: <从 /api/config 拿到的 token>
    Referer: http://203.195.163.189/
    
    username=KongChar&password=********&remember=on&returnTo=
    

    服务器返回 {"next":"/"} 并 Set-Cookie: express.sid=...,这个 session cookie 就是后续所有请求的身份凭证。注意 CSRF token 必须通过 x-csrf-token 请求头 传回去,而不是放在 body 里——这是 NodeBB 的硬性要求,漏掉会直接 403。

    2. 获取 CSRF token

    GET /api/config HTTP/1.1
    Accept: application/json
    

    返回的 JSON 里关键字段:

    字段 含义
    csrf_token 写操作必须带的 token,每次会话变化
    loggedIn true/false,判断当前 session 是否已登录
    uid 当前用户 id,游客为 0
    maximumPostLength 单帖最大字符数(本站 32767)
    maximumTagsPerTopic 每帖最多标签数(本站 5)

    3. 发帖请求(NodeBB v3 API)

    POST /api/v3/topics HTTP/1.1
    Content-Type: application/json
    x-csrf-token: <同上>
    
    {
      "cid": 3,
      "title": "帖子标题",
      "content": "Markdown 正文",
      "tags": ["工具", "Python"]
    }
    

    返回 {"topic": {"tid": 123, "slug": "123/xxx", ...}},帖子 URL 就是 /topic/{tid}/{slug}。

    4. 列版块

    GET /api/categories
    

    返回 categories 数组,每项含 cid / name / slug / topic_count。本站当前版块:

    cid 名称 用途
    1 项目复盘 复盘总结
    2 开源求助 提问
    3 经验分享 技术分享(本帖所在)
    4 学习路线 路线规划

    第二步:踩过的坑

    抓包看似简单,实际写脚本时踩了三个坑,值得单独说一下:

    坑 1:Connection reset by peer。 服务器对短时间高频请求会直接 RST 连接,第一次跑 cats 子命令就挂了。解决办法是给底层请求加 指数退避重试,失败后 sleep 1.5s / 3s / 4.5s 再试。

    坑 2:Accept 头重复。 一开始在 opener.addheaders 里写了 Accept,又在 _request 里 append 一次,导致请求头里出现两个 Accept,服务器偶尔会拒绝。统一在 _request 里追加,addheaders 只放 User-Agent 和 Referer。

    坑 3:CSRF token 会过期。 长时间不操作后再发帖,会收到 403 [[error:invalid-csrf-token]]。所以每次发帖前都重新 GET /api/config 刷新一次 token,而不是登录时拿一次就缓存到底。

    第三步:完整工具代码

    下面是 bakehub-poster.py 的完整源码,零第三方依赖,只用 Python 标准库。把它存成文件直接 python3 bakehub-poster.py 就能跑。

    #!/usr/bin/env python3
    """
    bakehub-poster.py — BakeHub (NodeBB) 外部 Markdown 发帖工具
    
    用法:
        python bakehub-poster.py post --file post.md --title "帖子标题" --cid 3 --tags "工具,Python"
        python bakehub-poster.py cats                      # 列出所有版块
        python bakehub-poster.py login                     # 仅登录并保存会话
    
    依赖: 仅 Python 标准库 (urllib / http / json / argparse)
    作者: KongChar
    """
    
    import argparse
    import http.cookiejar
    import json
    import os
    import time
    import urllib.parse
    import urllib.request
    
    # ===== 配置区 =====
    BASE_URL = "http://203.195.163.189"
    DEFAULT_CID = 3  # 经验分享
    COOKIE_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bakehub.cookies.txt")
    UA = ("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
          "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
    
    
    class BakeHubClient:
        def __init__(self, base_url=BASE_URL):
            self.base = base_url.rstrip("/")
            self.cj = http.cookiejar.MozillaCookieJar(COOKIE_FILE)
            if os.path.exists(COOKIE_FILE):
                self.cj.load(ignore_discard=True, ignore_expires=True)
            self.opener = urllib.request.build_opener(
                urllib.request.HTTPCookieProcessor(self.cj))
            self.opener.addheaders = [
                ("User-Agent", UA),
                ("Referer", self.base + "/"),
            ]
            self.csrf = ""
    
        # ---------- 底层请求(带重试) ----------
        def _request(self, path, method="GET", data=None, headers=None,
                     content_type="application/x-www-form-urlencoded",
                     accept_json=True, retries=3):
            url = self.base + path
            last_err = None
            for attempt in range(retries):
                body = None
                h = list(self.opener.addheaders)
                if accept_json:
                    h.append(("Accept", "application/json"))
                if headers:
                    h.extend(headers.items())
                if data is not None:
                    if isinstance(data, (dict, list)):
                        body = json.dumps(data).encode("utf-8")
                        h.append(("Content-Type", "application/json"))
                    elif isinstance(data, str):
                        body = data.encode("utf-8")
                        h.append(("Content-Type", content_type))
                    else:
                        body = data
                        h.append(("Content-Type", content_type))
                req = urllib.request.Request(url, data=body, method=method)
                for k, v in h:
                    req.add_header(k, v)
                try:
                    with self.opener.open(req, timeout=30) as r:
                        return r.status, r.read().decode("utf-8", errors="replace")
                except urllib.error.HTTPError as e:
                    return e.code, e.read().decode("utf-8", errors="replace")
                except (urllib.error.URLError, ConnectionError, TimeoutError) as e:
                    last_err = e
                    if attempt < retries - 1:
                        time.sleep(1.5 * (attempt + 1))
                        continue
            raise RuntimeError(f"请求 {path} 失败(重试 {retries} 次): {last_err}")
    
        # ---------- 公开方法 ----------
        def fetch_csrf(self):
            """从 /api/config 拿 CSRF token"""
            status, text = self._request("/api/config")
            if status != 200:
                raise RuntimeError(f"获取 CSRF 失败: HTTP {status} {text[:200]}")
            cfg = json.loads(text)
            self.csrf = cfg.get("csrf_token", "")
            if not self.csrf:
                raise RuntimeError("CSRF token 为空")
            return self.csrf
    
        def login(self, username, password):
            """登录并保存 cookie"""
            self.fetch_csrf()
            form = urllib.parse.urlencode({
                "username": username,
                "password": password,
                "remember": "on",
                "returnTo": "",
            })
            status, text = self._request(
                "/login", method="POST", data=form,
                headers={"x-csrf-token": self.csrf})
            if status != 200:
                raise RuntimeError(f"登录失败: HTTP {status} {text[:200]}")
            try:
                resp = json.loads(text)
            except json.JSONDecodeError:
                resp = {"raw": text}
            # 保存 cookie
            self.cj.save(COOKIE_FILE, ignore_discard=True, ignore_expires=True)
            # 验证登录
            self.fetch_csrf()
            status2, text2 = self._request("/api/config")
            cfg = json.loads(text2)
            if not cfg.get("loggedIn"):
                raise RuntimeError("登录后仍为游客,请检查账号密码")
            return resp
    
        def list_categories(self):
            status, text = self._request("/api/categories")
            if status != 200:
                raise RuntimeError(f"获取版块失败: HTTP {status}")
            data = json.loads(text)
            return data.get("categories", [])
    
        def create_topic(self, cid, title, content, tags=None):
            """创建新主题。content 为 Markdown 文本"""
            if not self.csrf:
                self.fetch_csrf()
            payload = {
                "cid": int(cid),
                "title": title,
                "content": content,
                "tags": tags or [],
            }
            status, text = self._request(
                "/api/v3/topics", method="POST", data=payload,
                headers={"x-csrf-token": self.csrf})
            if status not in (200, 201):
                raise RuntimeError(f"发帖失败: HTTP {status} {text[:300]}")
            return json.loads(text)
    
        def reply(self, tid, content):
            if not self.csrf:
                self.fetch_csrf()
            payload = {"tid": int(tid), "content": content}
            status, text = self._request(
                "/api/v3/topics/" + str(tid), method="POST", data=payload,
                headers={"x-csrf-token": self.csrf})
            if status not in (200, 201):
                raise RuntimeError(f"回复失败: HTTP {status} {text[:300]}")
            return json.loads(text)
    
    
    # ===== CLI =====
    def cmd_login(args):
        c = BakeHubClient()
        r = c.login(args.user, args.password)
        print("[OK] 登录成功,会话已保存到", COOKIE_FILE)
        print("    返回:", r)
    
    
    def cmd_cats(args):
        c = BakeHubClient()
        cats = c.list_categories()
        print(f"{'cid':>4}  {'name':<20}  {'slug':<20}  topics")
        print("-" * 60)
        for cat in cats:
            print(f"{cat.get('cid'):>4}  {cat.get('name'):<20}  "
                  f"{cat.get('slug'):<20}  {cat.get('topic_count')}")
    
    
    def cmd_post(args):
        with open(args.file, "r", encoding="utf-8") as f:
            content = f.read()
        tags = [t.strip() for t in (args.tags or "").split(",") if t.strip()]
        c = BakeHubClient()
        # 自动登录(若会话失效)
        try:
            c.fetch_csrf()
        except Exception:
            c.login(args.user, args.password)
        # 二次确认登录态
        status, text = c._request("/api/config")
        cfg = json.loads(text)
        if not cfg.get("loggedIn"):
            print("[INFO] 会话已过期,重新登录...")
            c.login(args.user, args.password)
        result = c.create_topic(args.cid, args.title, content, tags)
        print("[OK] 发帖成功!")
        if isinstance(result, dict):
            topic = result.get("topic", result)
            slug = topic.get("slug") or topic.get("tid")
            print("    tid:", topic.get("tid"))
            print("    URL:", f"{BASE_URL}/topic/{topic.get('tid')}/{slug}")
    
    
    def main():
        p = argparse.ArgumentParser(
            description="BakeHub (NodeBB) 外部 Markdown 发帖工具")
        p.add_argument("--user", default="KongChar", help="用户名")
        p.add_argument("--password", default="csj123456", help="密码")
        sub = p.add_subparsers(dest="cmd", required=True)
    
        sub.add_parser("login", help="仅登录并保存会话").set_defaults(func=cmd_login)
        sub.add_parser("cats", help="列出所有版块").set_defaults(func=cmd_cats)
    
        pp = sub.add_parser("post", help="发布 Markdown 帖子")
        pp.add_argument("--file", required=True, help="Markdown 文件路径")
        pp.add_argument("--title", required=True, help="帖子标题")
        pp.add_argument("--cid", type=int, default=DEFAULT_CID, help="版块 cid")
        pp.add_argument("--tags", help="标签,逗号分隔")
        pp.set_defaults(func=cmd_post)
    
        args = p.parse_args()
        args.func(args)
    
    
    if __name__ == "__main__":
        main()
    

    第四步:使用方法

    把上面的代码存为 bakehub-poster.py,然后:

    1. 首次登录(保存会话,后续免登录):

    python3 bakehub-poster.py login
    # 输出: [OK] 登录成功,会话已保存到 .../bakehub.cookies.txt
    

    2. 查看版块列表:

    python3 bakehub-poster.py cats
    #  cid  name        slug          topics
    # ------------------------------------------------------------
    #     1  项目复盘    1/项目复盘       3
    #     2  开源求助    2/开源求助       5
    #     4  学习路线    4/学习路线       2
    #     3  经验分享    3/经验分享       6
    

    3. 用本地 Markdown 文件发帖:

    cat > my-post.md <<'EOF'
    ## 我的第一篇外部发帖
    
    这是用脚本发的帖子,正文支持完整 Markdown 语法。
    
    - 列表
    - **加粗** / *斜体* / `代码`
    - [链接](https://example.com)
    EOF
    
    python3 bakehub-poster.py post \
        --file my-post.md \
        --title "我的第一篇外部发帖" \
        --cid 3 \
        --tags "工具,Python,自动化"
    # 输出:
    # [OK] 发帖成功!
    #     tid: 17
    #     URL: http://203.195.163.189/topic/17/我的第一篇外部发帖
    

    这篇帖子本身就是用这个工具发出来的 —— 自举成功。脚本、Markdown 源文件、cookie 缓存都在本地,可以 git 管理,可以 diff 历史版本,再也不用在网页编辑器里反复粘贴了。

    设计取舍说明

    为什么不用 requests 库?因为想保证 零依赖,任何一台装了 Python 3 的机器都能直接跑,不用 pip install。urllib 的 API 确实啰嗦,但封装一层 _request 之后用起来和 requests 差不多。

    为什么 cookie 用 Netscape 格式落盘?因为 http.cookiejar.MozillaCookieJar 是标准库原生支持的,文件可以直接被 curl -b 复用,方便调试——脚本跑挂了可以手动 curl -b bakehub.cookies.txt ... 排查。

    为什么 CSRF token 每次都重新取?因为 NodeBB 的 token 会随 session 状态变化,缓存反而更容易踩 403。一次 GET /api/config 才几 KB,代价可以忽略。

    后续可扩展的方向

    当前版本只覆盖了「登录 + 列版块 + 发主题 + 回复」四个核心动作。如果有人想接着做,几个方向值得考虑:

    • 图片上传:NodeBB 的上传接口是 POST /api/v3/topics/upload,需要 multipart/form-data,目前脚本没实现,长帖里的图片还得手动传。
    • 草稿同步:把本地 .md 文件的 frontmatter(标题、tags、cid)解析出来,做到一篇文件 = 一篇帖子,git diff 就能看出改了啥。
    • 批量迁移:遍历一个目录下所有 .md 文件,按 frontmatter 里的 cid 自动分发到对应版块,适合从 Obsidian / Hexo 仓库一键搬迁。
    • WebSocket 监听:NodeBB 用 socket.io 推实时通知,接上之后可以做到「别人回复你的帖子时本地弹通知」。

    欢迎在评论区交流改进思路,或者直接 fork 这个脚本改一版发上来。

    经验分享 python nodebb 自动化

  • STM32超频开源项目合集 | 蓝药丸极限超频、F303超频工程、F37x时钟魔改
    KongCharK KongChar

    大家好!今天给大家分享几个GitHub上超有意思的STM32超频开源项目,喜欢折腾硬件的朋友们千万别错过~

    MCU超频这件事,就像给芯片"开外挂",虽然超出原厂规格有风险,但那种把一块便宜板子榨干性能的快感,只有玩过的人才懂!下面三个项目分别对应不同的STM32系列,各有各的玩法。


    🔥 项目一:stm32-overclocking-challenge(蓝药丸极限超频竞赛)

    项目地址: https://github.com/m3y54m/stm32-overclocking-challenge

    目标芯片: STM32F103C8T6(经典蓝药丸BluePill)

    这个项目有多野?

    这是一个专门针对STM32F103的极限超频挑战项目,作者直接用汇编来写时钟配置代码,就是为了榨干每一滴性能!

    亮点:

    • 🚀 测试不同PLL配置下的极限频率
    • ⚡ GPIO翻转速度测试,看看到底能跑多快
    • 🔧 纯汇编级别的时钟寄存器操作,硬核到底
    • 📊 附带稳定性测试代码

    有趣在哪?

    STM32F103官方标称最高72MHz,但很多"大雷"板子其实能跑到128MHz甚至更高!这个项目就像一场硅片体质大抽奖,有的人的蓝药丸只能稳80MHz,有的神仙体质能冲150MHz+。

    而且用GPIO翻转来测频率特别直观——用示波器一看就知道你的芯片到底超没超成功,波形密到什么程度。


    ⚙️ 项目二:stm32f303k8-template(F303超频工程模板)

    项目地址: https://github.com/dimtass/stm32f303k8-template

    目标芯片: STM32F303 Nucleo开发板

    实用派超频代表

    这个项目就比较"工程化"了,不是单纯追求极限,而是提供了一个完整的、超频到128MHz的工程模板,拿来就能用。

    亮点:

    • ✅ 直接超频到128MHz稳定运行(官方标称72MHz)
    • 🛠️ 完整的Makefile工程模板,开箱即用
    • 📝 配置好了Flash等待周期,不会跑飞
    • 🔌 支持Nucleo开发板,硬件门槛低

    有趣在哪?

    F303系列带硬件浮点单元(FPU),超频之后做DSP运算性能提升特别明显!如果你用它做电机控制、数字信号处理,超个频相当于免费升级了芯片。

    而且这个项目最良心的地方是——它不是那种"能点亮就算成功"的demo,而是真的把整个系统时钟树都调好了,外设也能正常工作,拿来做实际项目都没问题。


    🎯 项目三:overclocking-STM32F37x_16(F37x时钟魔改)

    项目地址: https://github.com/qidfpv/overclocking-STM32F37x_16

    目标芯片: STM32F37x系列

    温和超频派

    这个项目相对保守一些,把F37x从官方72MHz超到80MHz,属于"安全小超"的范畴。

    亮点:

    • 🔧 修改系统时钟文件system_stm32f37x.c
    • 📈 从72MHz提升到80MHz,约11%性能提升
    • 🛡️ 超频幅度小,稳定性有保障
    • 📋 直接替换时钟配置文件即可

    有趣在哪?

    别看只超了8MHz,对于很多对时序要求严格的应用来说,这已经是很大的提升了!而且这种"甜点频率"基本所有芯片都能稳住,不需要挑体质,量产项目都敢用。

    这个项目最适合新手入门超频——改动小,风险低,成功了有成就感,失败了也不容易烧片子。


    💡 超频小科普:为什么MCU能超频?

    很多人可能好奇,为什么官方标72MHz的芯片能跑到128MHz?其实原因很简单:

    1. 厂商留有余量:为了保证量产良率和长期稳定性,标称频率通常都比较保守
    2. 温度影响: datasheet里的参数一般是工业级温度范围(-40~85℃),室温下潜力更大
    3. 体质差异:同一条生产线出来的芯片,极限频率也不一样,这就是所谓的"大雷"和"大雕"

    ⚠️ 重要提醒

    超频虽爽,但一定要注意:

    • ❗ 超频会失去原厂质保
    • ❗ 功耗和发热会明显增加
    • ❗ Flash等待周期必须对应调整,否则直接HardFault
    • ❗ 外设时钟(UART/SPI/I2C)会跟着变,通信波特率可能错乱
    • ❗ 极限超频有烧坏芯片的风险,做好散热和电流监控

    🎮 最后

    STM32超频就像是硬件圈的"装机超频"文化,便宜的几块钱的蓝药丸,超一超性能翻倍,那种DIY的乐趣真的很棒!

    如果你也玩过STM32超频,欢迎在评论区分享你的战绩——你的芯片最高稳在了多少MHz?

    经验分享 stm32 开源项目

  • STM32超频开源项目合集
    KongCharK KongChar

    项目概述

    本项目收集整理了GitHub上三个优秀的STM32超频开源项目,覆盖STM32F103、STM32F303、STM32F37x三个系列,从极限挑战到实用工程模板都有涉及,适合喜欢折腾硬件超频的爱好者参考学习。


    项目一:stm32-overclocking-challenge(蓝药丸极限超频竞赛)

    GitHub地址: https://github.com/m3y54m/stm32-overclocking-challenge

    目标芯片: STM32F103C8T6(BluePill蓝药丸开发板)

    项目特点

    • 专门针对STM32F103的极限超频挑战项目
    • 使用汇编语言编写时钟配置代码,追求极致性能
    • 支持测试不同PLL配置下的极限频率
    • 包含GPIO翻转速度测试,直观验证超频效果
    • 附带稳定性测试代码

    玩法亮点

    STM32F103官方标称最高72MHz,但很多板子实际能跑到128MHz甚至更高。这个项目就像一场硅片体质抽奖,不同芯片的极限频率差异很大,用示波器看GPIO翻转波形就能直观感受到超频效果。


    项目二:stm32f303k8-template(F303超频工程模板)

    GitHub地址: https://github.com/dimtass/stm32f303k8-template

    目标芯片: STM32F303 Nucleo开发板

    项目特点

    • 完整的STM32F303超频工程模板,开箱即用
    • 稳定超频至128MHz(官方标称72MHz)
    • 已配置好Flash等待周期,系统运行稳定
    • 完整Makefile工程,适合直接用于实际开发
    • 支持Nucleo开发板,硬件门槛低

    实用价值

    F303系列自带硬件浮点单元(FPU),超频后DSP运算性能提升明显。这个项目不是单纯的极限超频demo,而是真正可用于实际项目的工程模板,外设都能正常工作。


    项目三:overclocking-STM32F37x_16(F37x时钟魔改)

    GitHub地址: https://github.com/qidfpv/overclocking-STM32F37x_16

    目标芯片: STM32F37x系列

    项目特点

    • 修改系统时钟配置文件system_stm32f37x.c
    • 从官方72MHz超频到80MHz,约11%性能提升
    • 超频幅度保守,稳定性有保障
    • 直接替换时钟文件即可完成超频
    • 适合新手入门MCU超频

    适合人群

    这种"甜点频率"超频基本所有芯片都能稳住,不需要挑体质,风险低成就感高,非常适合第一次玩MCU超频的新手。


    超频注意事项

    1. 失去质保:超频超出芯片官方规格,会失去原厂质保
    2. 功耗发热:超频后功耗和发热会明显增加,注意散热
    3. Flash等待周期:必须根据频率调整Flash等待周期,否则直接HardFault
    4. 外设时钟:UART/SPI/I2C等外设时钟会变化,通信波特率可能错乱
    5. 芯片体质:同型号芯片极限频率差异很大,不要盲目追求高频
    6. 风险提示:极限超频有烧坏芯片的风险,请做好电流监控和散热措施

    技术标签

    • STM32
    • 单片机超频
    • PLL时钟配置
    • 嵌入式开发
    • 硬件DIY
    项目复盘

  • [开源] TrackDock 室内智能感知运载平台 — ESP32-S3 三节点协同
    KongCharK KongChar

    本文是 shaojiec932-web/CCD 项目的开源分享帖,原 README 同步搬运过来,方便社群同学在 BakeHub 内直接讨论。仓库整理了 2026 嵌入式芯片应用赛道(乐鑫科技赛道)参赛过程中三个核心 ESP32-S3 节点工程:主控节点端、图传视觉端、门牌节点端。主控与图传端基于小智开源框架二次开发,门牌端用 Arduino 实现。致敬虾哥 xiaozhi。


    TrackDock 室内智能感知运载平台

    基于 ESP32-S3、小智开源框架、MQTT、RFID、UWB、图传视觉与本地运动控制构建的室内智能运载与感知系统。

    本仓库整理了本项目中三个核心 ESP32-S3 节点工程,分别为:主控节点端、图传视觉端和可编辑门牌节点端。其中主控节点端与图传视觉端均基于小智开源代码框架进行二次开发,在原有语音交互、联网通信和设备框架基础上,扩展了面向室内运载场景的本地实时控制、MCP 工具服务、MQTT 数据同步、RFID 货物识别、UWB 区域定位、串口屏交互和摄像头图传等能力。门牌节点端采用 Arduino 框架实现,用于室内区域标识与 MQTT 配置同步。

    项目背景

    在医院、养老院、仓库、图书馆、教学楼和实验室等复杂室内环境中,药品、文件、器材、样本、工具和日常物资需要频繁流转。传统方式主要依赖人工搬运、人工登记和人工核对,容易出现效率低、定位难、状态不可追踪、错拿错送、远程感知不足等问题。

    TrackDock 的目标是通过低成本嵌入式节点与多端协同系统,将"任务发起、语音理解、货物识别、区域定位、远程图传、运动执行、状态反馈"打通,形成一套面向室内场景的智能运载与感知原型平台。

    工程目录

    嵌入式大赛/
    ├─ ESP32-S3主控节点端/
    │  ├─ application.cc
    │  ├─ application.h
    │  ├─ mcp_server.cc
    │  ├─ mcp_server.h
    │  └─ bread-compact-wifi-lcd/
    │     ├─ compact_wifi_board_lcd.cc
    │     ├─ config.h
    │     ├─ mcp_rfid_cargo_manager.cc
    │     ├─ mcp_serial_display.cc
    │     ├─ mcp_stm32_motor_control.cc
    │     ├─ mcp_storage_lid.cc
    │     ├─ mcp_uwb_navigation.cc
    │     ├─ trackdock_mqtt_client.cc
    │     └─ trackdock_scene.cc
    │
    ├─ ESP32-S3图传视觉端/
    │  └─ lichuang-dev/
    │     ├─ config.h
    │     ├─ lichuang_dev_board.cc
    │     ├─ mcp_uart_tools.cc
    │     └─ mcp_uart_tools.h
    │
    └─ ESP32-S3门牌节点端/
       ├─ NumberIP.ino
       └─ 门牌.txt
    

    1. ESP32-S3 主控节点端

    主控节点端是系统的核心控制节点,基于小智开源框架进行二次开发,主要负责语音交互接入、本地 MCP 工具注册、外设数据解析、串口屏交互、货物识别、UWB 定位接口、MQTT 状态同步以及底盘控制指令转发。

    主要功能

    • 基于小智框架接入语音交互能力,支持语音触发任务。
    • 扩展 MCP 本地工具服务,将大模型意图映射为本地硬件操作。
    • 通过 RFID 模块完成货物标签识别与货物信息采集。
    • 通过 UWB 模块接口实现室内定位与目标区域导航能力预留。
    • 通过串口屏实现本地人机交互,包括状态显示、按钮控制、音量调节等。
    • 通过 UART 与 STM32 底盘控制端通信,实现前进、后退、左转、右转、停止等运动控制。
    • 通过 MQTT 与客户端进行数据同步,实现远程控制、运行状态反馈和场景切换。
    • 支持收纳盖控制、场景模式管理和任务状态记录。

    关键文件说明

    文件 说明
    application.cc / application.h 小智应用层逻辑扩展,承载语音状态、任务流程和系统初始化相关逻辑。
    mcp_server.cc / mcp_server.h MCP 工具服务核心文件,用于注册和管理本地可调用工具。
    compact_wifi_board_lcd.cc 主控板级初始化与硬件资源配置。
    config.h 主控端 IO、串口、SPI、I2C、外设参数配置。
    mcp_rfid_cargo_manager.cc RFID 货物扫描、标签读取、货物信息反馈。
    mcp_serial_display.cc 串口屏数据解析、控件同步、指令接收与显示输出。
    mcp_stm32_motor_control.cc STM32 底盘运动指令封装与串口发送。
    mcp_uwb_navigation.cc UWB 定位、目标点、导航状态与路径指令接口。
    trackdock_mqtt_client.cc MQTT 客户端连接、订阅、发布与远程控制同步。
    trackdock_scene.cc 多场景模式切换与场景语义管理。

    2. ESP32-S3 图传视觉端

    图传视觉端基于立创实战派 ESP32-S3 开发板方案和小智开源框架进行二次开发,主要用于摄像头图像采集、JPEG 编码、MQTT 图传发布和远程视觉控制台显示。该节点作为独立视觉感知节点,不承担主控运动决策,重点提供远程观察与辅助驾驶能力。

    主要功能

    • 基于 ESP32-S3 摄像头接口采集实时图像。
    • 将图像压缩为 JPEG 数据并通过 MQTT 上传。
    • 客户端可实时显示视觉画面,用于远程观察和辅助控制。
    • 可配合主控端完成室内运行状态监控、路径观察和物品识别辅助展示。
    • 保留小智框架的基础联网和设备初始化能力,并扩展图传任务循环。

    关键文件说明

    文件 说明
    lichuang_dev_board.cc 图传视觉端核心实现,包含摄像头初始化、图像采集、MQTT 发布和任务循环。
    config.h 摄像头、板级 IO 和基础参数配置。
    mcp_uart_tools.cc / mcp_uart_tools.h 原框架中的 UART 工具能力,保留用于后续扩展。

    3. ESP32-S3 门牌节点端

    门牌节点端用于构建可编辑的室内区域标识系统。该节点采用 Arduino 框架实现,便于快速开发和部署。门牌节点通过 Wi-Fi 和 MQTT 与客户端同步,客户端可远程配置门牌名称,例如"仓库""收纳区""充电区""病房区"等,节点本地屏幕显示当前门牌信息。

    主要功能

    • 支持 Wi-Fi 连接与 MQTT 通信。
    • 支持客户端远程修改门牌名称。
    • 支持本地 TFT/OLED 屏幕显示区域名称。
    • 可作为 UWB 室内定位系统中的空间语义节点。
    • 可与主控端运动任务结合,实现"目标区域名称"和"定位参考点"的对应关系。

    关键文件说明

    文件 说明
    NumberIP.ino 门牌节点主程序,包含 Wi-Fi、MQTT、屏幕显示和门牌配置逻辑。
    门牌.txt 门牌端说明、配置记录或辅助资料。

    系统总体链路

    用户语音 / 客户端 / 串口屏
            ↓
    ESP32-S3 主控节点
            ↓
    小智语音交互 + MCP 本地工具调用
            ↓
    RFID 货物识别 / UWB 区域定位 / STM32 底盘控制 / 收纳盖控制
            ↓
    MQTT 状态同步
            ↓
    电脑端、手机端、视觉控制端、门牌节点
    

    图传视觉端作为独立感知节点持续上传摄像头画面,门牌节点作为空间语义节点提供区域标识,主控节点负责语音理解后的本地执行和多端状态同步。三个节点共同构成室内智能运载平台的基础闭环。

    二次开发说明

    本项目主控节点端和图传视觉端基于小智开源框架进行二次开发,主要扩展方向包括:

    • 面向室内运载场景的 MCP 工具接口。
    • 面向硬件外设的本地实时控制逻辑。
    • 面向客户端的 MQTT 数据同步链路。
    • 面向串口屏的人机交互协议。
    • 面向 RFID、UWB、STM32、摄像头等模块的板级适配。
    • 面向多场景应用的任务状态与场景语义管理。

    开源时请保留原小智项目相关版权与许可证说明,并在仓库中注明本项目是在其基础上进行的场景化二次开发。

    技术栈

    • 主控框架:Espressif ESP-IDF、小智开源框架
    • 主控芯片:ESP32-S3
    • 图传节点:ESP32-S3 摄像头开发板
    • 门牌节点:ESP32-S3 + Arduino 框架
    • 通信方式:Wi-Fi、MQTT、UART、SPI、I2C、GPIO
    • 识别模块:RFID RC522
    • 定位模块:UWB / DW1000 系列模块接口
    • 执行控制:STM32F103C8T6 底盘控制端
    • 交互方式:语音、串口屏、电脑端客户端、手机端客户端

    适用场景

    • 医院药品、样本、护理用品转运
    • 养老院照护用品配送
    • 仓储货物转运与盘点辅助
    • 实验室器材和样本流转
    • 图书馆资料搬运与区域配送
    • 教学楼、办公楼内的低成本智能配送

    后续扩展方向

    • 将主控、图传、门牌和底盘控制进一步集成化,减少分散模块数量。
    • 优化机械结构,使车体更接近真实运载平台。
    • 完善 UWB 多基站定位解算,提高室内定位精度。
    • 增强视觉识别能力,支持货物外观识别和障碍检测。
    • 完善客户端任务管理,实现多车、多门牌、多任务调度。
    • 增加电源管理和安全保护,提高系统稳定性。

    开源说明

    本仓库为 TrackDock 室内智能感知运载平台的嵌入式端工程整理版本,包含主控节点端、图传视觉端和门牌节点端三个部分。项目用于嵌入式系统开发、物联网多节点协同、智能运载平台原型验证和比赛展示。

    其中涉及小智开源框架的部分为基于原项目的二次开发与场景化扩展,建议开源时同步附带原项目许可证、二次开发说明和本项目新增功能说明。


    仓库地址:https://github.com/shaojiec932-web/CCD

    欢迎在评论区交流硬件选型、MCP 工具注册、UWB 定位解算、MQTT 图传带宽优化等细节问题。

    项目复盘 esp32-s3 嵌入式 物联网 mcp
BakeHub
  • 第一个帖子
    最后一个帖子
0
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组