当前位置: 首页 > article >正文

PX4自动驾驶仪启动流程与后台运作机制深度剖析

一、系统启动流程全景图PX4的启动过程可以清晰地分为三个层次Bootloader阶段 → NuttX RTOS启动 → PX4中间件与应用启动1.1 Bootloader阶段当飞行控制器上电时首先执行的是固化在芯片内部的Bootloader程序。核心功能基础硬件初始化时钟、内存、存储加载并验证主固件跳转到固件入口关键代码// platforms/nuttx/NuttX/nuttx/arch/arm/src/stm32_h7/stm32_h7b3xx_boot.c void __start(void) { /* 初始化堆栈指针 */ __asm__ __volatile__(\tldr sp, _estack\n); /* 清零BSS段 */ memset(__bss_start, 0, __bss_end - __bss_start); /* 复制数据段到RAM */ memcpy(__data_start, __data_load, __data_end - __data_start); /* 板级初始化 */ stm32_boardinitialize(); /* 跳转到主固件 */ nx_start(); }1.2 NuttX RTOS启动Bootloader跳转后NuttX实时操作系统开始初始化。初始化流程// nuttx/sched/init/nx_start.c void nx_start(void) { /* 1. 初始化系统数据结构 */ sched_initialize(); /* 2. 创建空闲任务 */ idle_task_create(); /* 3. 初始化设备驱动 */ drivers_initialize(); // 这里调用board_app_initialize() /* 4. 创建init任务 */ task_create(init, PRIO_INIT, STACK_INIT, init_task, NULL); }关键转折点 -board_app_initialize()// platforms/nuttx/src/px4/stm/px4fmu_common/stm32_boardinit.c int board_app_initialize(void) { /* 初始化硬件外设 */ stm32_serial_initialize(); // UART控制台 stm32_spi_initialize(); // SPI总线 stm32_i2c_initialize(); // I2C总线 stm32_pwm_initialize(); // PWM输出 stm32_adc_initialize(); // ADC采集 /* 挂载文件系统 */ mount(/dev/ram0, /etc, romfs, 0, NULL); mount(/dev/mmcsd0, /fs/microsd, vfat, 0, NULL); /* 创建PX4主任务 - 这才是真正的入口点 */ px4_task_spawn_cmd(init, SCHED_DEFAULT, SCHED_PRIORITY_DEFAULT, CONFIG_PTHREAD_STACK_DEFAULT, px4_main, (char * const *)NULL); return OK; }二、PX4中间件启动2.1px4_main()- PX4世界的大门// src/platforms/common/px4_common_init.cpp int px4_main(int argc, char *argv[]) { /* 1. 初始化PX4通用层 */ px4::init(argc, argv, px4); /* 2. 启动工作队列线程池 */ work_queue_manager_start(); /* 3. 执行启动脚本rcS - 这才是真正的核心 */ int ret rc_script_run(/etc/init.d/rcS); /* 4. 进入主循环 */ while (true) { px4_sleep(1); // 1秒休眠等待其他任务运行 } return 0; }2.2rcS脚本深度解析rcS脚本位于ROMFS文件系统中是PX4模块启动的总指挥。# ROMFS/px4fmu_common/init.d/rcS #!/bin/sh # 1. 参数系统初始化 param select /fs/mtd_params param load # 2. 传感器驱动启动 if [ $AUTOCNF yes ]; then # IMU驱动 mpu6000 start bmp280 start hmc5883 start # GPS驱动 gps start # 其他外设 tone_alarm start rgbled start fi # 3. 姿态估计启动 ekf2 start # 4. 控制器启动 mc_att_control start # 多旋翼姿态控制 mc_pos_control start # 多旋翼位置控制 # 5. 通信模块启动 mavlink start -d /dev/ttyS1 # USB mavlink start -d /dev/ttyS2 # TELEM1 # 6. 核心任务启动 sensors start # 传感器数据发布 commander start # 状态机与安全监控 logger start # 数据日志记录 navigator start # 任务导航三、后台运作机制3.1 系统架构图Commander (状态机)uORB消息总线 (所有模块通过它通信)传感器驱动EKF2控制器MAVLink(MPU6000)(姿态估计)(控制律)(通信协议)工作队列(Work Queue) - 处理耗时/阻塞任务NuttX RTOS内核 - 任务调度、中断管理3.2 uORB通信机制uORB是PX4模块间通信的核心采用发布-订阅模式。消息定义示例# msg/vehicle_attitude.msg uint64 timestamp # 时间戳 float32[4] q # 四元数 float32[4] delta_q_reset # 增量四元数 uint8 reset_counter # 重置计数器模块通信示例// 发布者EKF2模块 void EKF2::publish_attitude() { vehicle_attitude_s att; att.timestamp hrt_absolute_time(); matrix::Quatf q{_ekf.getQuaternion()}; q.copyTo(att.q); _att_pub.publish(att); // 发布到uORB总线 } // 订阅者姿态控制器 void MulticopterAttitudeControl::subscribe() { _att_sub orb_subscribe(ORB_ID(vehicle_attitude)); // 设置轮询fd _poll_fds[0].fd _att_sub; _poll_fds[0].events POLLIN; } void MulticopterAttitudeControl::run() { while (!should_exit()) { // 等待新消息 int ret px4_poll(_poll_fds, 1, 1000); if (ret 0 (_poll_fds[0].revents POLLIN)) { // 获取最新姿态 orb_copy(ORB_ID(vehicle_attitude), _att_sub, _att); // 执行控制律计算 control_attitude(); } } }3.3 工作队列(Work Queue)机制工作队列用于处理不适合在主循环中执行的耗时任务。// src/lib/work_queue/work_queue.h struct work_s { struct work_s *next; // 链表指针 void (*worker)(void *arg); // 工作函数 void *arg; // 参数 uint32_t qid; // 队列ID uint32_t delay; // 延迟时间 }; // 工作队列初始化 void work_queue_manager_start() { /* 创建高优先级工作队列 */ work_queue_create(g_hpwork, hpwork, PRIORITY_HPWORK, STACK_HPWORK); /* 创建低优先级工作队列 */ work_queue_create(g_lpwork, lpwork, PRIORITY_LPWORK, STACK_LPWORK); }典型应用场景// 传感器驱动中的使用 class MPU6000 : public SPI { private: struct work_s _work; // 工作项 static void work_callback(void *arg) { MPU6000 *dev (MPU6000 *)arg; dev-read_measurements(); // 读取传感器数据 dev-publish(); // 发布到uORB /* 重新调度 */ work_queue(HPWORK, dev-_work, (worker_t)MPU6000::work_callback, dev, USEC2TICK(1000)); // 1kHz } }; int MPU6000::start() { /* 初始调度 */ work_queue(HPWORK, _work, (worker_t)MPU6000::work_callback, this, USEC2TICK(1000)); return PX4_OK; }3.4 定时器机制PX4提供了高精度定时器用于周期性任务。// platforms/common/include/px4_platform_common/timer.h typedef void (*px4_timer_callback_t)(void *arg); int px4_timer_register(px4_timer_callback_t callback, void *arg, unsigned int usec, bool oneshot); int px4_timer_unregister(px4_timer_callback_t callback, void *arg);实际应用// 用于PWM输出 static void pwm_timer_callback(void *arg) { PWMOutput *pwm (PWMOutput *)arg; /* 更新PWM占空比 */ pwm-update_duty_cycle(); /* 如果需要复杂处理提交到工作队列 */ work_queue(LPWORK, pwm-_work, pwm_work_callback, pwm, 0); }四、核心模块交互流程4.1 传感器数据流[硬件中断] → [IMU驱动] → [传感器模块] → [EKF2] → [控制器] ↓ ↓ ↓ ↓ ↓ 触发读取 读取原始 校准、融合 状态估计 控制计算 数据具体实现// 1. IMU驱动 - 中断处理 int mpu6000::interrupt_handler(int irq, void *context) { /* 触发数据读取 */ work_queue(HPWORK, _work, (worker_t)mpu6000::read_data, this, 0); return 0; } // 2. 传感器模块订阅并处理 void Sensors::run() { // 订阅原始IMU数据 int accel_sub orb_subscribe(ORB_ID(sensor_accel)); while (true) { orb_copy(ORB_ID(sensor_accel), accel_sub, accel); // 校准 apply_calibration(accel); // 发布校准后的IMU数据 _vehicle_imu_pub.publish(imu); } } // 3. EKF2订阅并融合 void Ekf2::run() { int imu_sub orb_subscribe(ORB_ID(vehicle_imu)); while (true) { orb_copy(ORB_ID(vehicle_imu), imu_sub, imu); // EKF更新 _ekf.update(imu); // 发布估计结果 publish_attitude(); publish_local_position(); } }4.2 控制流[Commander] → [位置控制器] → [姿态控制器] → [混控器] → [PWM输出] ↓ ↓ ↓ ↓ ↓ 模式切换 位置设定值 姿态设定值 电机混控 执行器输出控制循环示例// 姿态控制器主循环 void MulticopterAttitudeControl::Run() { /* 等待新数据 */ _att_sub.wait_for_update(); /* 获取当前姿态 */ orb_copy(ORB_ID(vehicle_attitude), _att_sub, _att); /* 获取姿态设定值 */ orb_copy(ORB_ID(vehicle_attitude_setpoint), _att_sp_sub, _att_sp); /* 计算角速率设定值 */ matrix::Vector3f rates_sp attitude_controller(_att.q, _att_sp.q); /* 发布角速率设定值 */ _rates_sp_pub.publish(rates_sp); } // 混控器处理 void Mixer::Run() { /* 订阅控制指令 */ orb_copy(ORB_ID(actuator_controls_0), _ctrl_sub, _ctrl); /* 混控计算控制值 - 电机PWM */ float outputs[ACTUATOR_COUNT]; _mixer-mix(_ctrl.control, outputs); /* 写入PWM设备 */ ioctl(_pwm_fd, PWM_SET_OUTPUTS, (unsigned long)outputs); }五、Commander状态机详解Commander是PX4的最高级状态机负责安全管理。5.1 状态定义// src/modules/commander/commander.h enum main_state_t { MAIN_STATE_MANUAL, // 手动模式 MAIN_STATE_ALTCTL, // 高度控制 MAIN_STATE_POSCTL, // 位置控制 MAIN_STATE_AUTO_MISSION, // 自动任务 MAIN_STATE_AUTO_LOITER, // 自动悬停 MAIN_STATE_AUTO_RTL, // 自动返航 MAIN_STATE_ACRO, // 特技模式 MAIN_STATE_OFFBOARD, // 外部控制 MAIN_STATE_STAB, // 增稳模式 MAIN_STATE_MAX }; enum arming_state_t { ARMING_STATE_INIT, // 初始化中 ARMING_STATE_STANDBY, // 待命(已上锁) ARMING_STATE_ARMED, // 已解锁 ARMING_STATE_ARMED_ERROR,// 解锁但有错误 ARMING_STATE_STANDBY_ERROR,// 待命但有错误 ARMING_STATE_REBOOT, // 重启中 ARMING_STATE_MAX };5.2 Commander主循环// src/modules/commander/commander.cpp void Commander::run() { /* 订阅所需数据 */ int battery_sub orb_subscribe(ORB_ID(battery_status)); int gps_sub orb_subscribe(ORB_ID(vehicle_gps_position)); int sensors_sub orb_subscribe(ORB_ID(sensor_combined)); while (!should_exit()) { /* 1. 更新状态 */ update_arming_state(); // 检查解锁条件 update_main_state(); // 根据RC/任务更新主模式 /* 2. 安全检查 */ check_battery_failsafe(); // 电池低电压保护 check_gps_failsafe(); // GPS丢失保护 check_rc_failsafe(); // 遥控器信号丢失保护 check_geofence_failsafe(); // 电子围栏保护 /* 3. 发布状态信息 */ publish_vehicle_status(); publish_vehicle_command_ack(); /* 4. 处理命令 */ handle_vehicle_commands(); /* 5. 250ms循环 */ usleep(250000); } }5.3 解锁条件检查bool Commander::check_arming_allowed() { /* 必须满足的条件 */ if (!_system_calibrated) { return false; // 未校准 } if (_battery-voltage BATTERY_LOW_THRESH) { return false; // 电池电压过低 } if (_sensor_failure) { return false; // 传感器故障 } /* 可选条件根据参数 */ if (_param_arm_without_gps.get() 0 !_gps_fix) { return false; // 需要GPS但无定位 } if (!_prearm_check_passed()) { return false; // 预检未通过 } return true; }六、总结与关键点6.1 启动流程要点Bootloader→NuttX→PX4三层递进board_app_initialize()是硬件与PX4的桥梁rcS脚本是应用启动的总指挥模块按依赖关系顺序启动驱动→估计器→控制器→通信→Commander6.2 后台运作要点uORB是模块间通信的神经网络工作队列处理耗时任务保证实时性定时器驱动周期性任务Commander是系统的大脑负责安全和状态管理6.3 代码文件索引功能关键文件说明启动入口stm32_boardinit.cboard_app_initialize()PX4主入口px4_common_init.cpppx4_main()启动脚本ROMFS/init.d/rcS模块启动顺序uORBsrc/modules/uORB/消息总线工作队列src/lib/work_queue/后台任务处理Commandersrc/modules/commander/状态机与安全EKF2src/modules/ekf2/姿态估计控制器src/modules/mc_att_control/控制律理解PX4的启动和运作机制不仅是阅读代码更要理解各模块如何通过uORB和工作队列协同工作。希望本文能帮助您更好地掌握PX4系统的精髓。

相关文章:

PX4自动驾驶仪启动流程与后台运作机制深度剖析

一、系统启动流程全景图PX4的启动过程可以清晰地分为三个层次:Bootloader阶段 → NuttX RTOS启动 → PX4中间件与应用启动1.1 Bootloader阶段当飞行控制器上电时,首先执行的是固化在芯片内部的Bootloader程序。核心功能:基础硬件初始化&#…...

阿里云第四季营收433亿:同比增36% 经调整EBITA为39亿

雷递网 乐天 3月19日阿里(纽交所代码:BABA及港交所代号:9988(港币柜台)及89988(人民币柜台))今日公布截至2025年12月31日止季度业绩。财报显示,阿里2025年第四季度营收为…...

MGeo开源地址模型部署教程:ModelScope镜像免配置环境快速上手

MGeo开源地址模型部署教程:ModelScope镜像免配置环境快速上手 1. 引言:为什么你需要一个“懂地址”的AI? 想象一下这个场景:你是一家外卖平台的工程师,每天要处理数百万条用户填写的地址。有的地址写“XX小区3号楼2单…...

java面经知识

一、java关键版本之间的区别:1、java8Lambda 表达式:函数式编程支持 Stream API:集合操作流式处理 新的日期时间 API:LocalDate、LocalDateTime 默认方法:接口中的 default 方法 Optional 类:空指针解决方案…...

通义千问3-Reranker-0.6B商业应用:SaaS知识管理平台重排模块集成方案

通义千问3-Reranker-0.6B商业应用:SaaS知识管理平台重排模块集成方案 1. 引言:智能重排技术如何提升知识管理效率 在现代SaaS知识管理平台中,用户最头疼的问题往往是:输入一个问题,系统返回了一大堆相关文档&#xf…...

Qwen3.5-9B算力适配:RTX 4090单卡部署9B MoE模型实操记录

Qwen3.5-9B算力适配:RTX 4090单卡部署9B MoE模型实操记录 1. 项目背景与模型特性 Qwen3.5-9B是阿里云推出的新一代混合专家(MoE)模型,在保持9B参数规模的同时,通过创新的架构设计实现了性能突破。该模型特别适合在消费级高性能GPU上部署&am…...

开源ASR新选择:SenseVoice-Small ONNX量化模型保姆级Gradio部署教程

开源ASR新选择:SenseVoice-Small ONNX量化模型保姆级Gradio部署教程 1. 快速了解SenseVoice-Small模型 SenseVoice-Small是一个专注于高精度多语言语音识别的开源模型,特别适合需要快速部署和高效推理的场景。这个模型采用了ONNX格式并进行了量化处理&…...

6.3 Web 服务器程序解释请求消息并作出响应

本文是《网络是怎样连接的》精读系列第 28 篇,全书逐章精讲、通俗拆解,帮你从零吃透计算机网络的底层逻辑。一、本节核心脉络:从 “网络数据包” 到 “用户可见内容” 的关键一跃当 TCP 模块将完整的 HTTP 请求交付给 Web 服务器程序时&#…...

AcousticSense AI场景应用:帮你自动整理杂乱音乐文件夹

AcousticSense AI场景应用:帮你自动整理杂乱音乐文件夹 1. 音乐管理的新思路 1.1 音乐整理的痛点 每个音乐爱好者都会遇到这样的困扰:下载的音乐文件散落在不同文件夹,文件名混乱无规律,有些甚至只显示为track01.mp3这样的默认…...

Qwen3-32B-Chat实战案例:为内容平台搭建AI审核+自动标签+SEO标题生成流水线

Qwen3-32B-Chat实战案例:为内容平台搭建AI审核自动标签SEO标题生成流水线 1. 项目背景与需求分析 内容平台每天面临海量用户生成内容(UGC)的管理挑战。传统人工审核方式存在效率低、成本高、标准不统一等问题。同时,内容标签分类和SEO标题优化也需要大…...

Win10永恒之黑漏洞复现实战:从蓝屏攻击到GetShell完整流程(附避坑指南)

Win10永恒之黑漏洞深度解析与实战复现:从原理到GetShell的全链路攻防 在网络安全领域,漏洞复现不仅是学习攻防技术的最佳途径,更是理解系统安全机制的重要窗口。CVE-2020-0796(永恒之黑)作为Windows SMB协议中的高危漏…...

GPU显存友好:Nanbeige 4.3B在消费级显卡上的流式神谕渲染实操

GPU显存友好:Nanbeige 4.3B在消费级显卡上的流式神谕渲染实操 1. 项目背景与价值 在AI对话应用领域,用户体验与性能优化往往难以兼得。Nanbeige 4.3B模型以其出色的对话能力和适中的模型规模,成为消费级显卡部署的理想选择。本文将重点介绍…...

Fish Speech 1.5常见问题解决:合成慢、效果差?看这篇就够了

Fish Speech 1.5常见问题解决:合成慢、效果差?看这篇就够了 1. 开篇:你的问题,这里都有答案 用上Fish Speech 1.5,本以为能轻松搞定各种语音合成需求,结果发现合成速度慢得像蜗牛?生成的语音听…...

RabbitMQ监控异常解析:Message rates活跃但Queued messages为零的深层原因

1. 为什么Message rates活跃但Queued messages为零? 最近在排查RabbitMQ监控数据时,发现一个有趣的现象:Message rates(消息速率)显示有波动,说明消息正在被生产和消费,但Queued messages&#…...

微信聊天记录全量备份与安全归档:WeChatExporter实现指南

微信聊天记录全量备份与安全归档:WeChatExporter实现指南 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 在数字化时代,微信聊天记录已成为个人和…...

MySQL安全加固十大必做措施

MySQL安全加固十大硬核操作大纲账户与权限管理禁用默认账户如root远程登录,创建专用管理账户遵循最小权限原则,使用GRANT精确分配权限定期审计用户权限,清理无效账户密码策略强化启用密码复杂度插件(如validate_password&#xff…...

Qwen3-32B企业级落地:制造业设备说明书生成、故障诊断建议、维修流程输出

Qwen3-32B企业级落地:制造业设备说明书生成、故障诊断建议、维修流程输出 1. 为什么制造业需要大模型 在制造业数字化转型浪潮中,设备文档管理一直是痛点。传统方式面临三大挑战: 文档制作成本高:一台复杂设备需要200页说明书&…...

自动驾驶规划控制-nmpc路径规划和mpc路径跟踪 matlab和simulink联合仿真,非...

自动驾驶规划控制-nmpc路径规划和mpc路径跟踪 matlab和simulink联合仿真,非线性mpc路径规划,线性mpc路径跟踪 最近在搞自动驾驶的规划控制方案,试了非线性MPC做路径规划线性MPC做跟踪的组合拳。实测发现这俩货配合起来效果挺带劲,…...

Nanbeige 4.1-3B效果展示:LV.99大贤者神谕逐字蹦出实录(附GIF)

Nanbeige 4.1-3B效果展示:LV.99大贤者神谕逐字蹦出实录(附GIF) 1. 复古像素风AI对话体验 Nanbeige 4.1-3B模型搭配全新设计的像素游戏风格前端,为用户带来独特的对话体验。这套界面完全颠覆了传统AI对话工具的极简风格&#xff…...

计算机毕业设计springboot基于Javaweb的助农管理系统 基于SpringBoot框架的农产品电商服务平台设计与实现 智慧农业信息管理系统——农户产销一体化平台开发

计算机毕业设计springboot基于Javaweb的助农管理系统453ruu73 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着信息技术的快速发展和农业现代化的深入推进,如何利…...

Python - 链表浅析

Python - 链表浅析 本篇用Python代码模拟链表 1. 链表介绍 概述 链表属于数据结构之 线性结构 的一种,每个节点都只能有 1个前驱 和 1个后继 节点。 作用 用于优化顺序表的弊端(如果没有足够的连续的内存空间,会导致扩容失败)。链…...

Qwen3.5-9B开源镜像保姆级教程:从pull到Gradio访问全流程

Qwen3.5-9B开源镜像保姆级教程:从pull到Gradio访问全流程 1. 前言:为什么选择Qwen3.5-9B Qwen3.5-9B是当前开源大模型领域的一颗新星,它在多个关键性能指标上超越了前代产品。作为一款多模态模型,它不仅能处理文本任务&#xff…...

分布式控制系统(DCS)安装:从方案设计到投运验收的完整指南

一、什么是分布式控制系统(DCS)安装分布式控制系统(Distributed Control System,简称 DCS)是一种面向流程工业的自动化控制平台,通常由操作员站、工程师站、控制器、I/O 模块、历史数据库、网络交换设备、现…...

【硬核裁剪手册】:基于ARM Cortex-M3/M4架构的RTOS内核最小化实践,含11项裁剪Checklist与编译时断言验证模板

第一章:RTOS内核裁剪的底层逻辑与ARM Cortex-M3/M4架构约束RTOS内核裁剪并非简单的功能开关,而是对调度器、中断管理、内存模型与硬件抽象层(HAL)之间耦合关系的深度解耦过程。其底层逻辑根植于嵌入式系统资源确定性与实时性保障的…...

Z-Image-GGUF新手必看:阿里通义模型提示词编写技巧与示例

Z-Image-GGUF新手必看:阿里通义模型提示词编写技巧与示例 1. 认识Z-Image-GGUF模型 1.1 什么是Z-Image-GGUF Z-Image-GGUF是阿里巴巴通义实验室开源的一款文生图AI模型,采用GGUF量化技术,能够在较低显存环境下运行。这个模型可以将文字描述…...

零基础学Python环境管理:Miniconda-Python3.8镜像保姆级入门指南

零基础学Python环境管理:Miniconda-Python3.8镜像保姆级入门指南 你是不是也遇到过这样的烦恼?想在自己的电脑上跑一个AI项目,结果光是安装Python和各种库就折腾了一整天,最后还因为版本冲突报了一堆错。或者,你需要在…...

CHORD-X在网络安全领域的应用:威胁情报自动分析与汇总报告生成

CHORD-X在网络安全领域的应用:威胁情报自动分析与汇总报告生成 1. 引言:当安全警报淹没你的收件箱 每天早上九点,安全分析师小李打开电脑,面对的是上百封未读邮件:CVE漏洞公告、防火墙告警、入侵检测系统日志、威胁情…...

释放90%存储空间的ComfyUI资源优化与性能提升指南:5步实现系统轻量化

释放90%存储空间的ComfyUI资源优化与性能提升指南:5步实现系统轻量化 【免费下载链接】ComfyUI-Manager 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-Manager ComfyUI作为强大的开源AI工作流工具,随着使用时间增长,自定义节…...

【Python】学习笔记 - P2

【Python】学习笔记 - P21. 字符串str定义和切片1.1 定义方式1.2 切片方式1.3 字符串的相关方法1.3.1 查找1.3.2 修改2. 列表list及其应用场景2.1 列表的定义2.2 列表的相关操作2.1.1 增加2.1.2 查找2.1.3 删除2.1.4 修改2.3 列表的循环遍历1. 字符串str定义和切片 1.1 定义方…...

小白也能玩转AI看图说话:OFA图像描述镜像一键部署教程

小白也能玩转AI看图说话:OFA图像描述镜像一键部署教程 1. 从零开始:什么是AI看图说话? 你有没有想过,给电脑看一张照片,它就能像人一样,把照片里的内容用文字描述出来?听起来很科幻&#xff0…...