Buildroot 增加系统启动项并解决后台无法获取输入(串口)

在这里插入图片描述

概述

Buildroot 是一款轻量级、高度可定制的开源工具集,专为嵌入式系统打造。它通过自动化构建流程(交叉编译工具链、Linux内核、根文件系统、引导程序),将复杂的嵌入式开发简化为“菜单配置”(make menuconfig)。开发者无需手动处理依赖与兼容性问题,只需勾选所需软件包,即可生成完整的可烧录镜像。在嵌入式场景中,服务进程的自动加载是刚需, 通常将启动脚本置于/etc/init.d/(SysV init)或编写systemd单元文件,实现服务的全自动托管。

增加模块

参考: Buildroot 添加自定义模块-内置文件到文件系统

–本文不再复述–

源码结构

package/auto_run/
├── CMakeLists.txt
├── Config.in
├── dumpsys.cpp
├── auto_run.mk
└── S99dumpsys

编写测试程序

dumpsys.cpp

#include <stdio.h>
#include <string.h>
#include <sys/statvfs.h>
#include <unistd.h>

void print_memory() {
    FILE *meminfo = fopen("/proc/meminfo", "r");
    if (!meminfo) {
        printf("无法读取内存信息\n");
        return;
    }

    char line[256];
    unsigned long total_mem = 0, free_mem = 0;

    while (fgets(line, sizeof(line), meminfo)) {
        if (strncmp(line, "MemTotal:", 9) == 0) {
            sscanf(line + 9, "%lu", &total_mem);
        } else if (strncmp(line, "MemFree:", 8) == 0) {
            sscanf(line + 8, "%lu", &free_mem);
        }
    }
    fclose(meminfo);

    printf("可用内存: %lu MB / 最大内存: %lu MB\n", free_mem / 1024, total_mem / 1024);
}

void print_disk() {
    struct statvfs stat;
    if (statvfs("/", &stat) != 0) {
        printf("无法读取磁盘信息\n");
        return;
    }

    unsigned long free_space = (stat.f_bfree * stat.f_frsize) / (1024 * 1024);
    unsigned long total_space = (stat.f_blocks * stat.f_frsize) / (1024 * 1024);

    printf("可用空间: %lu MB / 最大空间: %lu MB\n", free_space, total_space);
}

int main() {
    char input[10];

    while (1) {
        printf("输入命令 (mem/disk/exit): ");
        if (!fgets(input, sizeof(input), stdin)) {
            continue;
        }

        // 移除换行符
        input[strcspn(input, "\n")] = 0;

        if (strcmp(input, "mem") == 0) {
            print_memory();
        } else if (strcmp(input, "disk") == 0) {
            print_disk();
        } else if (strcmp(input, "exit") == 0) {
            break;
        } else {
            printf("无效命令\n");
        }
    }
    return 0;
}

编译测试

编译完成后, 可以直接将dumpsys 程序拷贝到/usr/data/dumpsys运行测试:

# /usr/data/dumpsys 
输入命令 (mem/disk/exit): mem
可用内存: 397 MB / 最大内存: 447 MB
输入命令 (mem/disk/exit): exit

增加系统自启动

auto_run.mk

AUTO_RUN_SITE = $(TOPDIR)/package/auto_run
AUTO_RUN_SITE_METHOD = local
AUTO_RUN_INSTALL_STAGING = YES

# dumpsys
define AUTO_RUN_INSTALL_INIT_SYSV
    $(INSTALL) -D -m 0755 $(AUTO_RUN_SITE)/S99dumpsys $(TARGET_DIR)/etc/init.d/S99dumpsys
endef

AUTO_RUN_POST_INSTALL_TARGET_HOOKS += AUTO_RUN_INSTALL_INIT_SYSV

$(eval $(cmake-package))

S99dumpsys

#!/bin/sh

check_run(){
    local file="/usr/data/dumpsys"
    local max_attempts=10
    local attempt=1

    while [ $attempt -le $max_attempts ]; do
        if [ -f "$file" ]; then
            echo "File $file found, starting dumpsys..."
            /usr/data/dumpsys &
            return 0
        else
            echo "Attempt $attempt: File $file not found, waiting..."
            sleep 1
            attempt=$((attempt + 1))
        fi
    done

    echo "file not found and exit"
    return 1
}

case "$1" in
    start)
        echo "Starting dumpsys..."
        check_run || exit 1
        ;;
    stop)
        echo "Stopping dumpsys..."
        killall dumpsys
        ;;
    restart)
        $0 stop
        $0 start
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

exit 0

一切准备就绪! 打包烧录!

一个问题

为了方便测试, 默认/usr/data/目录下没有dumpsys, 通过命令拷贝并重启.
意外出现:

输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): 输入命令 (mem/disk/exit): ...

循环输出LOG: 输入命令 (mem/disk/exit):
调试发现问题出在

if (!fgets(input, sizeof(input), stdin))

原因是从stdin读取输入出现了问题.

在Buildroot环境中,fgets()在通过init脚本启动时失败但在手动启动时正常,这通常与标准输入(stdin)的环境差异有关。

由于 后台运行(&)的影响

  • &使程序在后台运行,可能导致stdin被关闭或重定向
  • init系统可能进一步处理了标准流

解决方案:显式指定输入设备

修改程序代码:

FILE *input_stream = fopen("/dev/console", "r");
if (!input_stream) {
    input_stream = fopen("/dev/tty", "r");
}
if (!input_stream) {
    input_stream = stdin;
}

if (!fgets(input, sizeof(input), input_stream)) {
    // 错误处理
}

根本原因是初始化环境和交互式shell环境的差异。在系统启动时,标准输入可能没有绑定到有效的终端设备,而手动启动时则会有完整的终端环境。

其他

/etc/init.d 目录下的 SXXxxx 文件作用解析‌

文件命名规则与核心作用‌

  • S 前缀‌:表示 ‌启动(Start)‌ 服务,与之对应的 K 前缀表示 ‌停止(Kill)‌ 服务‌。
    XX 数字‌:决定脚本执行顺序,数值小的优先执行(如 S10network 先于 S20apache 执行),用于解决服务间的依赖关系(例如网络接口需先于 Web 服务启动)‌。
    xxx 服务名‌:标识具体服务(如 S50ssh 表示 SSH 服务)。

  • SXXxxx 文件是 SysVinit/BusyBox 初始化系统中,通过数字排序和符号链接机制实现服务按需启动的核心配置单元,直接影响嵌入式设备或服务器在特定运行级别的服务状态‌。

### 配置和搭建YOLOv8环境 为了在特定环境下成功配置运行YOLOv8模型,可以按照以下方法操作: #### 1. 安装依赖 首先需要安装必要的Python库以及YOLOv8所需的框架。推荐使用虚拟环境隔离目依赖。 ```bash pip install ultralytics ``` 此命令将自动下载 `ultralytics` 库及其所有必需的依赖[^4]。 如果目标环境中存在CUDA支持,则可以通过额外安装PyTorch CUDA版本加速训练过程。例如,在具有CUDA 11.7兼容性的设备上可执行如下命令: ```bash pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117 ``` 这一步骤确保了GPU资源能够被充分利用以提升性能[^5]。 #### 2. 下载预训练权重文件 对于快速测试或迁移学习场景下,可以从官方仓库获取已有的预训练权重文件。这些权重经过大量数据集上的优化调整,有助于减少新任务中的收敛时间。 访问 Ultralytics GitHub 页面或者直接利用脚本拉取对应版本号下的最佳参数集合: ```python from ultralytics import YOLO model = YOLO('yolov8n.pt') # 加载nano规模的小型网络作为例子 ``` 上述代码片段展示了加载名为 yolov8n 的轻量级检测器实例化对象的方式[^6]。 #### 3. 数据准备与标注格式转换 为了让自定义的数据源适配YOLO算法的要求,需将其转化为标准形式——COCO JSON 或者 Pascal VOC XML 文件之一。此外还需注意图片尺寸统一性和标签框坐标的规范化处理等问题[^7]。 假设采用 COCO 格式的JSON描述符存储类别信息及边界框位置关系时,应保证字段名称严格遵循约定俗成的标准命名规则,比如 image_id, bbox 等关键字不可随意更改以免引起解析错误。 #### 4. 训练设置与超参调节 完成前期准备工作之后即可进入正式训练阶段。通过修改配置文件来指定各重要属性值如批量大小(batch size), 学习率(learning rate),周期数目(number of epochs)等等均会对最终效果产生深远的影响。 以下是简单的调用样例用于启动本地机器上的单卡分布式作业流程: ```python results = model.train( data='path/to/dataset.yaml', imgsz=640, batch=-1, epochs=100, name='custom_training_run' ) ``` 其中data参数指向包含路径映射关系在内的yaml元数据文档;imgsz控制输入分辨率大小;batch设为负数则允许程序自行决定最优批处理数量;epochs定义总的迭代轮次上限[^8]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值