尧图精选

PX4 中的 TensorFlow Lite Micro (TFLM) 神经网络集成指南

🕒 发布时间:2026/10/2 1:38:21 📁 来源:尧图网络
嵌入式物联网机器人自动驾驶智能硬件【免费下载链接】PX4-AutopilotPX4 Autopilot Software项目地址https://gitcode.com/gh_mirrors/px/PX4-Autopilot点击查看免费下载本篇技术指南深入讲解 PX4 如何将 TensorFlow Lite MicroTFLM推理库集成进mc_nn_control多旋翼神经网络控制模块从.tflite模型格式与 C 数组转换、xxd转换命令到 Resolver 算子注册、MicroInterpreter 初始化、输入/输出张量填充与推理调用的完整代码链路。读完本文你将掌握如何把自行训练的网络替换进 PX4 固件并理解其底层推理机制。TFLM 与 mc_nn_control 模块概览PX4 的 MC Neural Networks Control 模块mc_nn_control参见 modules_controller集成了一个基于 TensorFlow Lite Micro (TFLM) 推理库的神经网络。TFLM 是专为嵌入式设备设计的成熟推理库因此在 PX4 上是一个合适的选择。mc_nn_control是一个端到端的神经网络控制系统它订阅 uORB 消息获取状态量用神经网络计算控制输出再直接发布到执行机构话题。该示例模块替换了整个控制器结构以及控制分配器其模块级数据流如下模块从位置设定点出发最终直接输出四路电机指令绕过了传统的姿态/速率控制器与控制分配链路。神经网络部分的工作全部围绕 TFLM 展开网络以 C 数组形式内嵌在固件中由 TFLM 的解释器在飞控上完成前向推理。TFLM 神经网络格式TFLM 使用其自有的 tflite 格式 作为网络载体。但许多微控制器没有原生文件系统支持无法在运行时读取.tflite文件因此通常需要将一个 tflite 文件转换为 C 源文件和头文件直接编译进固件。mc_nn_control正是采用这种做法TFLite 神经网络在代码中由control_net.cpp和control_net.hpp两个文件表示。其中control_net.hpp声明网络数据与大小constexpr unsigned int control_net_tflite_size 15088; extern const unsigned char control_net_tflite[];control_net.cpp以 16 字节对齐的字节数组存放完整的 tflite 模型内容alignas(16) const unsigned char control_net_tflite[] { 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, ...从control_net.cpp的字节流中可以辨认出serving_default、output_0、args_0以及CONVERSION_METADATA、min_runtime_version2.20.0-dev20250323、schema 版本 2.0.0 等 TFLite 模型内部结构印证了这是一个标准的 flatbuffer 序列化 tflite 模型。该模型约 15 KB相比典型视觉模型小得多适合直接内嵌进飞控闪存。获取 tflite 格式的网络生成.tflite格式网络有很多在线资源。本文示例中的网络是在开源 Aerial Gym Simulator 中训练的Aerial Gym 自带教程既支持控制任务也支持基于视觉的导航任务的强化学习RL。项目在resources/conversion文件夹中提供了PyTorch - TFLM的转换代码。用你自己的神经网络更新 mc_nn_control如果你训练了自己的网络例如针对你自己的机架做了系统辨识详见 mc_neural_network_control 的 Training your own Network 一节可以按以下步骤将其替换进mc_nn_control。首先在 Ubuntu 终端中用xxd将.tflite网络转换成一个.cc文件xxd -i converted_model.tflite model_data.ccxxd -i会生成一个 C 数组数组名取自文件名以及对应的长度宏例如unsigned int converted_model_tflite_len。然后修改control_net.hpp和control_net.cpp纳入model_data.cc中的数据取.cc文件末尾的网络大小替换control_net.hpp中的control_net_tflite_size当前为15088。取.cc文件中模型数组的数据替换control_net.cpp中control_net_tflite[]数组的内容。完成后重新编译 PX4mc_nn_control需要与固件一起重新构建即可运行你自己的网络。代码详解control_net.cpp 中的集成代码本节对照mc_nn_control.cpp中的真实实现逐段解释 TFLM 集成代码。算子注册与 Resolver推理前首先要创建 Resolver并注册运行神经网络推理所需的算子。这一步在mc_nn_control.cpp顶部的匿名命名空间中完成// This number should be the number of operations in the model, like tanh and fully connected using NNControlOpResolver tflite::MicroMutableOpResolver3; TfLiteStatus RegisterOps(NNControlOpResolver op_resolver) { // Add the operations to you need to the op_resolver TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected()); TF_LITE_ENSURE_STATUS(op_resolver.AddRelu()); TF_LITE_ENSURE_STATUS(op_resolver.AddAdd()); return kTfLiteOk; }MicroMutableOpResolver3尖括号中的数字3代表运行推理所需注册的算子数量。TFLM 提供了相当多受支持的算子完整列表见micro_mutable_op_resolver.h但最先进/复杂的算子不在其中——这是嵌入式推理库在功能与代码体积之间的取舍。在控制示例中网络是全连接结构因此使用AddFullyConnected()注册全连接算子激活函数是 ReLU所以调用AddRelu()每个神经元上还有偏置项因此用AddAdd()注册加法算子。如果你的网络包含其他算子如卷积、池化、tanh需要在这里相应增加数量并调用对应的注册函数例如把MicroMutableOpResolver3改成更大的数字。Interpreter解释器在InitializeNetwork()函数中首先设置从源文件和头文件加载的模型然后搭建解释器int MulticopterNeuralNetworkControl::InitializeNetwork() { // Initialize the neural network const tflite::Model *control_model ::tflite::GetModel(control_net_tflite); // Set up the interpreter static NNControlOpResolver resolver; if (RegisterOps(resolver) ! kTfLiteOk) { PX4_ERR(Failed to register ops); return -1; } constexpr int kTensorArenaSize 10 * 1024; static uint8_t tensor_arena[kTensorArenaSize]; _interpreter new tflite::MicroInterpreter(control_model, resolver, tensor_arena, kTensorArenaSize); if (_interpreter nullptr) { PX4_ERR(interpreter alloc failed); return -1; } // Allocate memory for the models tensors TfLiteStatus allocate_status _interpreter-AllocateTensors(); ... _input_tensor _interpreter-input(0); ... return PX4_OK; }这段代码取自 TFLM 官方文档并有详细说明。关键点是::tflite::GetModel(control_net_tflite)直接从内嵌的字节数组解析 flatbuffer 模型无需文件系统。MicroInterpreter使用静态分配的tensor_arena张量竞技场此处为10 * 1024字节作为模型运行时的内存池这是 TFLM 在裸机/RTOS 上不依赖动态堆内存的核心机制。若模型变大需要相应增大该数组。AllocateTensors()为模型的张量分配内存失败时返回错误并清理解释器。最终_control_interpreter被设置好后续通过Invoke()成员函数运行推理_input_tensor也从_control_interpreter-input(0)取得用于后续填充输入数据。输入Inputs_input_tensor在PopulateInputTensor()函数中被填充。其原理是通过-data.f成员数组按索引写入网络要求的输入值。控制网络使用一个15 元素的一维输入数组顺序如下在 mc_neural_network_control 中有详细说明[0..2]局部位置误差目标位置 - 当前位置3 个值[3..8]三维旋转矩阵的前两行6 个值[9..11]线速度3 个值[12..14]角速度3 个值PopulateInputTensor()从 uORB 话题vehicle_local_position、vehicle_attitude、vehicle_angular_velocity、trajectory_setpoint收集数据并在函数内完成坐标变换PX4 使用 NED 坐标系而训练该网络的 Aerial Gym Simulator 使用 ENU 坐标系因此函数中构造了两个旋转矩阵frame_transf与frame_transf_2把所有输入从 NED 表示变换到 ENU 表示// Creates a 15 element input tensor for the neural network [pos_err(3), lin_vel(3), att(6), ang_vel(3)] ... matrix::Vector3f position_local matrix::Vector3f(_position.x, _position.y, _position.z); position_local frame_transf * frame_transf_2 * position_local; ... _input_tensor-data.f[0] trajectory_setpoint_local(0) - position_local(0); _input_tensor-data.f[1] trajectory_setpoint_local(1) - position_local(1); _input_tensor-data.f[2] trajectory_setpoint_local(2) - position_local(2); _input_tensor-data.f[3] _attitude_local_mat(0, 0); ... _input_tensor-data.f[12] angular_vel_local(0); _input_tensor-data.f[13] angular_vel_local(1); _input_tensor-data.f[14] angular_vel_local(2);ENU 与 NED 只是旋转表示方式不同平移差异仅为便于在同一图中显示两者如果要换成你自己的网络只需按照训练时定义的输入约定在此函数中提供相同的输入即可。输入完全可以按需改变——训练时用什么输入PX4 里就提供什么输入。输出Outputs输出的处理方式与输入类似。正确设置输入后调用Invoke()函数执行推理TfLiteStatus invoke_status _interpreter-Invoke(); ... _output_tensor _interpreter-output(0); if (_output_tensor nullptr) { PX4_ERR(Output tensor is null); return; } // Convert the output tensor to actuator values RescaleActions(); PublishOutput(_output_tensor-data.f);推理结果通过_control_interpreter-output(0)获取同样从输出张量的-data.f数组读出。该控制网络的输出是4 个值即四个电机的推力。由于 PX4 期望归一化的电机指令而 Aerial Gym Simulator 使用物理量RescaleActions()函数负责把网络输出转换为电机指令将网络输出限制在[-1, 1]区间使用参数MC_NN_THRST_COEF除以 100000将归一化输出换算为转速 rpssqrt关系体现推力正比于转速平方再结合MC_NN_MAX_RPM与MC_NN_MIN_RPM把 rpm 映射回归一化的[-1, 1]电机指令区间a 0.8的二次整形用于匹配电机的非线性响应。最终由PublishOutput(float *command_actions)把 4 路电机指令发布到 ActuatorMotors 话题actuator_motors.control[0] PX4_ISFINITE(command_actions[0]) ? command_actions[0] : NAN; actuator_motors.control[1] PX4_ISFINITE(command_actions[1]) ? command_actions[1] : NAN; actuator_motors.control[2] PX4_ISFINITE(command_actions[2]) ? command_actions[2] : NAN; actuator_motors.control[3] PX4_ISFINITE(command_actions[3]) ? command_actions[3] : NAN; // 其余 control[4..11] 置为 -NAN未使用如果神经网络控制模式反应过激或不够灵敏可以调节 MC_NN_THRST_COEF 参数减小以获得更大推力。构建集成把 TFLM 与 mc_nn_control 编入固件mc_nn_control的构建依赖在src/modules/mc_nn_control/CMakeLists.txt中声明px4_add_module( MODULE mc_nn_control MAIN mc_nn_control SRCS mc_nn_control.cpp mc_nn_control.hpp control_net.cpp control_net.hpp MODULE_CONFIG mc_nn_control_params.yaml DEPENDS tensorflow_lite_micro px4_work_queue mathlib ) target_link_libraries(mc_nn_control PRIVATE tensorflow_lite_micro)TFLM 库本身由src/lib/tensorflow_lite_micro/CMakeLists.txt提供它通过 git 子模块引入 tflite_micro 源码px4_add_git_submodule(TARGET git_tflite-micro PATH tflite_micro)收集tensorflow/lite/micro下的内核与框架源码编译为tensorflow_lite_micro库且仅在CONFIG_LIB_TFLMy时生效其第三方依赖flatbuffers、ruy、gemmlowp、CMSIS 等在构建时无需联网下载。mc_nn_control.hpp中对应的头文件包含为#include tflite_micro/tensorflow/lite/micro/micro_mutable_op_resolver.h #include tflite_micro/tensorflow/lite/micro/micro_interpreter.h #include tflite_micro/tensorflow/lite/schema/schema_generated.h在板级配置中启用模块与 TFLM 库通过 Kconfig 控制对应配置在src/modules/mc_nn_control/Kconfig与src/lib/tensorflow_lite_micro/Kconfig中定义。要把它加入某个板卡配置在对应default.px4board文件中加入两行CONFIG_LIB_TFLMy CONFIG_MODULES_MC_NN_CONTROLy官方已在多种配置上测试过可直接本地构建例如make px4_sitl_neuralmake px4_fmu-v6c_neuralmake mro_pixracerpro_neural需要注意该模块要求Ubuntu 24.04 或更新版本不支持 Ubuntu 22.04。mc_nn_control模块大约占用 50 KB 闪存而许多default.px4board配置的闪存已接近占满。要为神经网络控制模块腾出空间可以移除其他模块如 FW、rover、VTOL、UUV的包含语句。自动启动与参数模块通过参数MC_NN_EN控制是否开机自动启动——ROMFS/px4fmu_common/init.d/rc.mc_apps启动脚本会检查该参数if param compare -s MC_NN_EN 1 then mc_nn_control start fi相关参数在src/modules/mc_nn_control/mc_nn_control_params.yaml中定义参数类型默认值范围说明MC_NN_ENboolean1-为 true 时神经网络控制在开机时自动启动MC_NN_MAX_RPMint32220000 ~ 80000用于神经网络输出归一化的电机最大 RPMMC_NN_MIN_RPMint3210000 ~ 80000用于神经网络输出归一化的电机最小 RPMMC_NN_THRST_COEFfloat1.20.0 ~ 5.0电机推力系数用于归一化网络输出实际使用时除以 100000MC_NN_MANL_CTRLboolean1-是否允许用手动控制设定轨迹设定点修改后需重启运行时的推理与调试观测模块作为一个 WorkItem 挂载在nav_and_controllers工作队列上以角速度话题vehicle_angular_velocity的更新作为触发源见_angular_velocity_sub{this, ORB_ID(vehicle_angular_velocity)}。每次触发时Run()完成更新订阅 →PopulateInputTensor()填充输入 →_interpreter-Invoke()推理 →RescaleActions()归一化 →PublishOutput()发布actuator_motors。为了观测推理性能模块发布了 NeuralControl 调试话题记录 15 维观测向量、4 维网络输出以及控制器总耗时与推理耗时uint64 timestamp # [us] Time since system start float32[15] observation # Observation vector (pos error (3), att (6d), lin vel (3), ang vel (3)) float32[4] network_output # Output from neural network int32 controller_time # [us] Time spent from input to output int32 inference_time # [us] Time spent for NN inference这些消息归属于日志的debug类别要在飞行日志中保存它们需要把debug加入SDLOG_PROFILE参数。小结TFLM 在 PX4 中的集成是一条清晰、可复用的链路训练出.tflite模型 → 用xxd -i转换为 C 数组 → 替换control_net.hpp/control_net.cpp→ 按需调整 Resolver 算子注册数量与类型 → 修改PopulateInputTensor()的输入约定 → 重新编译固件。理解 Resolver、MicroInterpreter、张量竞技场与输入/输出张量这四个核心概念后你就能把这一端到端神经网络控制方案迁移到自己的机架、任务乃至其他控制器替换场景中。赞分享嵌入式物联网机器人自动驾驶智能硬件【免费下载链接】PX4-AutopilotPX4 Autopilot Software项目地址https://gitcode.com/gh_mirrors/px/PX4-Autopilot点击查看免费下载相关推荐10个sentence-bert-swedish-cased-openmind应用场景提升NLP项目效率10个sentence bert swedish cased openmind应用场景提升NLP项目效率 sentence bert swedish case构建AI生态的基石深入解析MCP Registry架构与实战部署构建AI生态的基石深入解析MCP Registry架构与实战部署 在AI应用开发日益复杂的今天如何高效管理和发现可复用的AI能力组件成为了开发者面临的核心挑后端AI Agent工具调用GetQzonehistory 使用指南把 QQ 空间历史说说导出到本地 ExcelGetQzonehistory 使用指南把 QQ 空间历史说说导出到本地 Excel GetQzonehistory 是一个 QQ 空间说说备份工具它把当前网页爬虫数据分析上一篇如何用awesome-python-webapp快速搭建你的第一个Python网站下一篇protoc-gen-gorm 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →