diff --git "a/\350\275\257\344\273\266(Software)/ROS/ROS2/(ZhaoCake-2026-02)\345\205\263\344\272\216ROS2\347\232\204DDS\351\200\232\344\277\241.md" "b/\350\275\257\344\273\266(Software)/ROS/ROS2/(ZhaoCake-2026-02)\345\205\263\344\272\216ROS2\347\232\204DDS\351\200\232\344\277\241.md" new file mode 100644 index 0000000..28dea0c --- /dev/null +++ "b/\350\275\257\344\273\266(Software)/ROS/ROS2/(ZhaoCake-2026-02)\345\205\263\344\272\216ROS2\347\232\204DDS\351\200\232\344\277\241.md" @@ -0,0 +1,167 @@ +# 关于ROS2的DDS通信 + +如果你以后要从事 ROS 2 相关的工作,那么 DDS 就是一个必然会遇到的核心话题。什么是 DDS?它有什么作用?为何它如此重要? + +## 1. 引言:ROS 1 的阿喀琉斯之踵 + +在正式介绍 DDS 之前,我们不妨先回顾一下 ROS 1 时代的那些“陈年旧账”。 + +### 痛点回顾 + +如果你做过 ROS 1 的多机通信项目,你一定有过这样的痛苦回忆: + +- **唯一的“大脑” (Roscore)**:ROS 1 强依赖于一个中心主节点 `roscore`。如果它挂了,整个系统就瘫痪了。这种单点故障(Single Point of Failure)让它很难应用于对可靠性要求极高的工业场景。 +- **IP 配置噩梦**:在多机通信时,你需要小心翼翼地配置 `ROS_MASTER_URI` 和 `ROS_IP`。一旦 WiFi 信号不好导致 IP 变动,或者网络配置稍有差错,连接就会瞬间断开,且很难自动恢复。 +- **“一刀切”的通信模式**:ROS 1 底层基于 TCP/UDP。虽然 TCP 提供了可靠传输,UDP 提供了低延迟,但它们缺乏针对机器人应用场景的精细化控制。比如:“我希望这个雷达数据尽可能快,丢包也无所谓”和“我希望这个控制指令绝对可靠,慢一点没关系”在 ROS 1 中很难灵活切换和共存。 + +### 引入主角:DDS + +ROS 2 的变革不仅是 API 的换皮,更是一次底层的换血。其中最大的改变,就是引入了 **DDS (Data Distribution Service)** 标准作为其通信中间件。 + +**核心论点:** DDS 不是简单的“换个协议”,而是将 ROS 从“科研玩具”推向“工业级应用”的关键一步。它赋予了 ROS 2 真正的分布式能力、实时性保障以及工业级的可靠性。 + +--- + +## 2. 什么是 DDS?(概念扫盲) + +### 定义 + +DDS(Data Distribution Service)是由 **OMG (Object Management Group)** 组织制定的一套工业级数据分发标准。 +在此之前,它早已在美军舰艇作战系统、金融高频交易、航空航天等对数据实时性和可靠性要求极高的领域证明了自己的价值。简单来说,它是通信界的“特种部队”。 + +### 核心架构:DCPS + +DDS 的核心理念是 **DCPS (Data-Centric Publish-Subscribe)**,即“以数据为中心的发布-订阅”。 + +- **传统网络编程**:关注的是“连接”。建立 Socket -> 维护连接 -> 发送数据。如果连接断了,你需要处理重连逻辑。 +- **DDS**:关注的是“数据”。我只关心“我要发什么数据”或者“我要收什么数据”。至于数据怎么切片、怎么路由、丢包了怎么重发、网络断了怎么缓存,统统交给 DDS 中间件处理。**“不管你怎么传,我只要数据到了就行。”** + +### ROS 2 的架构 + +为了兼容不同的 DDS 实现,ROS 2 设计了一个巧妙的抽象层。 + +顶层:User Code (你的 C++/Python 代码) +第二层:ROS Client Library (rclcpp / rclpy) +第三层:RMW (ROS Middleware Interface, 中间件抽象层) +底层:DDS Implementation (FastDDS, CycloneDDS, RTI Connext, etc.) + +### 亮点:RMW (ROS Middleware) + +ROS 2 并不绑定某一个特定的 DDS 库。通过 RMW 层,你可以像给汽车换轮胎一样,根据你的需求切换底层的 DDS 厂商: + +- **Fast DDS (eProsima)**:默认实现,功能全面,开源社区活跃。 +- **Cyclone DDS (Eclipse)**:小巧精悍,资源占用低,也是很多项目的首选。 +- **RTI Connext**:商业化方案,功能最强,但要花钱。 + +这种设计的好处是,你不需要修改一行应用层代码,只需要改一个环境变量,就能瞬间切换通信内核。 + +> 笔者最早接触到DDS相关概念就是在学习Navigation2库的时候涉及到了更换前两个DDS库。 + +--- + +## 3. 核心机制一:去中心化的“自动发现” (Discovery) + +### 问题解决 + +还记得 ROS 1 那个必须要先启动的 `roscore` 吗?在 ROS 2 中,**Master 节点消失了**。 + +### 工作原理 + +ROS 2 的节点是如何在茫茫网络中找到彼此的呢?这归功于 DDS 的 **RTPS (Real-Time Publish Subscribe)** 协议自带的自动发现机制。 + +1. **大喇叭广播 (Multicast)**:当一个节点启动时,它会向局域网内的一个预定多播地址(Multicast Address)发送“公告”: + > “我是节点 A,我发布 Topic X,我订阅 Topic Y,我的 QoS 是 Z。” +2. **建立连接**:局域网内的其他节点听到这个广播后,会检查自己的发布/订阅列表。如果发现匹配(Topic 名相同且 QoS 兼容),它们就会与新节点建立点对点的单播(Unicast)连接。 + +### 优势 + +- **零配置**:只要在同一个局域网(且支持多播),节点开机即连,无需指定 Master IP。 +- **高容错**:真正的分布式系统。任何一个节点(哪怕是原来的核心节点)崩溃,都不会影响其他节点之间的通信。 +- **动态扩展**:随时加入新机器,系统自动感知。 + +--- + +## 4. 核心机制二:QoS(服务质量)—— 博客的重头戏 + +### 为什么需要 QoS? + +现实世界中的网络环境是复杂的,不仅 WiFi 会丢包,带宽也有限。更重要的是,在机器人系统中,不同的数据有着完全不同的“身价”和“时效性”。 +DDS 允许我们为每个 Topic 甚至每个发布者/订阅者定制 **QoS (Quality of Service)** 策略,这是 ROS 1 完全不具备的能力。 + +### 四大核心 QoS 策略详解 + +#### 1. Reliability(可靠性):丢包了怎么办? + +- **Best Effort (尽力而为)**:只管发,不管你收没收到。适合高频传感器数据。 + - *场景*:激光雷达点云(10Hz)。如果丢了一帧,没关系,下一帧马上就来了。重传旧数据反而会阻塞新数据。 + - *图解*:投手疯狂扔球,不管捕手接没接住。 +- **Reliable (可靠传输)**:保证数据必达,如果丢包会重传。适合关键控制指令。 + - *场景*:机械臂关节目标位置。如果指令丢了,机械臂就不动了,所以必须确认收到。 + - *图解*:投手扔球,必须确认捕手接到了,没接到就重扔。 + +#### 2. History(历史记录):新数据来了,旧的留不留? + +- **Keep Last (只留最新的)**:配合 `depth` 参数(例如 depth=1),只保留最后 N条数据。 + - *场景*:里程计数据 (Odom)。通常我们只需要机器人当前在哪,1秒前的位置已经过时了。 +- **Keep All (全部保留)**:保留所有历史数据,直到内存爆掉。 + - *场景*:黑匣子日志、调试数据。 + +#### 3. Durability(持久性):迟到的订阅者能看到数据吗? + +- **Volatile (易失)**:数据发出去那一刻,如果没有人订阅,数据就消失了。后来加入的订阅者收不到以前的数据。 + - *场景*:机器人的瞬时速度。 +- **Transient Local (局部持久化)**:发布者会保存最后发布的数据(类似“公告板”),无论订阅者何时上线,都能立即收到最后一条消息。 + - *场景*:**静态地图 (Map)**。地图通常只发一次(Late-joiner problem)。如果不用 Transient Local,新启动的导航节点将永远收不到地图数据。 + +#### 4. Liveliness(活跃度):你还活着吗? + +DDS 可以监测节点的“心跳”。如果一个传感器节点承诺“每秒至少发一次数据”,但突然哑火了,系统判定其死亡,并可以触发急停或其他安全策略。 + +### 代码:如何配置 QoS + +光说不练假把式,我们看看在 Python (rclpy) 中如何定义一个“传感器专用”的 QoS: + +```python +from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy + +# 定义一个类似“传感器数据”的 QoS 配置 +# 目的:高吞吐低延迟,丢了不可惜,只看最新的 +sensor_qos = QoSProfile( + reliability=ReliabilityPolicy.BEST_EFFORT, # 尽力而为 + history=HistoryPolicy.KEEP_LAST, # 只留最新的 + depth=1 # 队列深度为 1 +) + +# 创建发布者时应用该 QoS +pub = node.create_publisher(LaserScan, 'scan', sensor_qos) +``` + +### ⚠️ 避坑指南:兼容性陷阱 (Compatibility) + +这是新手最容易踩的坑,**请务必注意**: +发布者 (Publisher) 和订阅者 (Subscriber) 的 QoS 必须**兼容**才能建立连接。 + +- **规则**:发布者的“承诺”必须满足订阅者的“要求”。 +- **典型错误**:发布者是 `Best Effort`(比较随意),而订阅者要求 `Reliable`(非常严格)。这时 DDS 会认为“我满足不了你的要求”,导致连接无法建立。结果就是:`ros2 topic list` 能看到 topic,但 `ros2 topic echo` 啥也没有! + +--- + +## 5. 进阶特性:DDS 带来的其他红利 + +- **实时性 (Real-time)**:很多 DDS 实现(如 Iceoryx 结合 CycloneDDS)支持**零拷贝 (Zero Copy)**。在大数据量传输(如 4K 摄像头图像)时,指针传递代替内存复制,极大降低了 CPU 占用和延迟。 +- **安全性 (SROS 2)**:基于 DDS-Security 标准,ROS 2 原生支持加密和认证。没有证书的黑客即使接入网络,也无法解析数据或发送控制指令,防止机器人被恶意劫持。 + +--- + +## 6. 总结与展望 + +DDS 的引入,让 ROS 2 相比 ROS 1 变得更加**复杂**(配置项多了,门槛高了),但也让它变得无比**强大**(适应工业、自动驾驶、医疗等苛刻场景)。 + +**作为开发者的建议:** +不要只使用默认的 QoS 配置。在写代码前,先想一想这个 Topic 的数据特性: + +- 它是“雷达点云”还是“控制指令”? +- 它是“瞬时状态”还是“全局配置”? +- 它需要“拼命发”还是“确认收”? + +理解了 DDS,你就掌握了 ROS 2 的灵魂。 diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-202601)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-01)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" similarity index 86% rename from "\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-202601)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" rename to "\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-01)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" index b533420..52f8c9b 100644 --- "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-202601)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" +++ "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-01)Renode\344\273\277\347\234\237\345\257\274\350\247\210.md" @@ -3,6 +3,7 @@ Renode 是面向嵌入式与异构硬件的开源仿真平台,可在无实物硬件的情况下进行固件开发、系统级调试与自动化测试。 ## 工业界运用 + 虽然在国内大众视野中 Renode 相对小众,但在全球嵌入式与半导体顶尖领域,它正逐渐成为标准工具栈的一部分,掌握它意味着接触最前沿的开发模式: - **Google (TensorFlow Lite / Zephyr)**:Google 使用 Renode 进行 TensorFlow Lite for Microcontrollers (TFLM) 的持续集成测试,确保机器学习模型在不同嵌入式平台上的兼容性。同时,Zephyr RTOS 项目官方 CI 也大量使用 Renode 进行多架构(ARM, RISC-V, Xtensa等)的每日构建测试。 @@ -15,16 +16,22 @@ Renode 是面向嵌入式与异构硬件的开源仿真平台,可在无实物 > 现在教学上依然常用的Proteus则是玩具。 ## 对个人的帮助 + - **降低入门成本**:无需实体硬件即可学习与验证。 - **提升调试效率**:可重复的仿真环境便于问题定位。 - **支持自动化**:脚本化测试帮助构建个人级持续验证流程。 ## 文档计划 -1. 基本的Renode使用 -2. Renode仿真SoC中的裸机开发 -3. Renode仿真SoC中的RTOS开发 -4. Renode仿真SoC中的神经网络模型部署 +- [x] [基本的Renode使用](./(ZhaoCake-2026-02)Renode是怎样工作的.md) +- [ ] Renode仿真SoC中的裸机开发 +- [ ] Renode仿真SoC中的RTOS开发 +- [ ] Renode仿真SoC中的神经网络模型部署 完成这四个基本的文档作为例子之后我将会提出 doc request issue 来请求更多文档。 +## 参考实验 + +实验仓库尚在开发中 + +[learning_renode](https://github.com/ZhaoCake/learning_renode) diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-02)Renode\346\230\257\346\200\216\346\240\267\345\267\245\344\275\234\347\232\204.md" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-02)Renode\346\230\257\346\200\216\346\240\267\345\267\245\344\275\234\347\232\204.md" new file mode 100644 index 0000000..d26ad30 --- /dev/null +++ "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/(ZhaoCake-2026-02)Renode\346\230\257\346\200\216\346\240\267\345\267\245\344\275\234\347\232\204.md" @@ -0,0 +1,183 @@ +# Renode 是怎样工作的 + +要学习Renode,首先需要明确Renode是什么,为什么要用Renode而不是其他的仿真工具。 +这就需要理解Renode的工作逻辑。 + +## 为什么使用Renode? + +### Renode与Qemu对比 + +在仿真领域,QEMU 无疑是行业老大哥,但 Renode 的出现并不是为了重复造轮子,而是为了解决现代嵌入式开发(特别是 IoT)中 QEMU 难以覆盖的痛点。 + +我们可以把 QEMU 比作“高性能跑车”,而把 Renode 比作“高精度乐高积木”。 + +| 维度 | QEMU (传统强者) | Renode (现代 IoT 仿真) | +| :--- | :--- | :--- | +| **核心定位** | **操作系统级仿真**。侧重于让另一个架构的 OS(如 Linux)在你的电脑上跑起来,追求速度。 | **系统/板级仿真**。侧重于模拟整个硬件系统(CPU + 外设 + 传感器 + 网络),追求可控性和可观测性。 | +| **配置方式** | **硬编码 (C语言)**。如果你想模拟一块新开发板,通常需要修改 QEMU 源码并重新编译,门槛极高。 | **文本配置 (.repl)**。通过人类可读的文本文件定义硬件(如 `0x4000: uart @ sysbus`),像搭积木一样拼装 SoC。 | +| **多节点支持** | **困难**。通常一个 QEMU 进程模拟一个设备,想模拟多台设备组网非常复杂。 | **原生支持**。可以在一个仿真环境中同时运行数十个节点(如 1 个网关 + 10 个传感器),并模拟它们之间的无线通信。 | +| **扩展性** | 修改源码,重新编译。 | 支持 Python/C# 脚本动态扩展,支持热插拔外设模型。 | +| **确定性** | 较难保证。多线程可能导致每次运行的时序微小差异。 | **严格确定性**。只要输入相同,无论运行多少次,指令执行的顺序和时间戳毫秒不差(对复现 Bug 至关重要)。 | + +### Renode与Proteus对比 + +我们来谈谈很多人都用过的Proteus。它确实开创了一种直观的模拟方式:从元件库中拖拽一个ATmega328P或8051,像画电路图一样连接LED、按钮和液晶屏,然后加载固件进行仿真。这种基于引脚和原理图的交互逻辑,非常适合理解单片机级的简单系统。 + +然而,当我们把目光投向现代嵌入式开发的主流——以Arm Cortex-M/R/A、RISC-V为代表的复杂SoC(System on Chip)时,Proteus的模型就显得“抱残守缺”、力不从心了。 这并非仅仅因为它支持的芯片型号老旧、更新缓慢,更深层的原因在于其底层的仿真范式已经与现代SoC的开发方式脱节。 + +Proteus进行的是原理图/PCB这一级的电平的仿真。而现代SoC的开发绝大多数关键外设(如UART、I2C、DMA、定时器)并非通过外部引脚与CPU连接,而是通过片内系统总线(如AHB、APB)直接与核心交换数据。这是一种更高层次、更高效的“内存映射I/O”通信。Proteus的引脚模型无法直观描述这种复杂的片内互联网络,强行用“虚拟导线”连接会变得极其复杂且不真实。并且Proteus也不能够适应当前的自动化的需求,图形的、拖拽的配置方式,显然是低效且难以自动工作的。 + +Proteus代表了以离散元器件和单片机为中心的旧时代仿真哲学。而现代嵌入式开发已经进入了以集成SoC和系统为核心的时代。Renode的诞生,正是为了应对这一转变。它摒弃了过时的“连线”思维,拥抱了“总线映射”和“系统描述”的范式,提供了与当代软硬件开发流程(如DevOps、Shift-Left测试)无缝衔接的能力。 + +### Renode是更现代的嵌入式仿真哲学 + +Renode 的设计哲学是 “将硬件抽象为软件对象”。基于这一理念,它带来了三大核心优势: + +1. 声明式硬件定义 (Declarative Hardware): 使用 .repl (Renode Platform) 文件,你可以用类似配置文件的语法,在几分钟内定义出一个全新的 SoC 或开发板,而无需编写一行 C 代码。 +2. 强大的内省与控制 (Introspection & Control): Renode 暴露了所有的内部状态。你可以随时暂停整个“世界”,查看任意寄存器、内存,甚至用 Python 脚本去“修改”传感器的数据(例如上一节提到的注入虚假温度数据)。 +3. 异构多节点仿真: 它可以在同一个模拟世界中,同时运行 RISC-V 的传感器、ARM Cortex-M 的控制器和 x86 的服务器,并模拟它们之间的蓝牙、Wi-Fi 或以太网通信。 + +在前面的导览中,我们也提到了,Renode尽管当前在国内名声不显,实际上在不少大型项目中已经有了很多应用。 + +但是对于一个学生而言,我认为Renode最关键的是给予了学生对于嵌入式更透明的视角。很多同学在嵌入式开发的过程当中更关注如何把功能 +跑起来,而没有在其背后的计算机体系结构方面做更多的关注,而这实际上很重要。Renode 不仅仅是一个“替代物理开发板”的工具,更是一个“计算机体系结构显微镜”。在没有Renode之前的实践中,我们可能需要自己在FPGA上跑软核、深入QEMU的源码才能看到的东西,现在Renode可以轻易看到了。 + +我不妨先问这样几个问题: + +1. 大家都知道 CPU 是按照它的 PC(程序计数器)指针在跑,那么系统上电的第一瞬间,你的这个 PC 值是从哪里来的呢?是谁告诉它的? +2. 为什么在开发板上通过拨动所谓的 BOOT 跳线帽,就可以修改从哪里启动(Flash 还是 RAM)?这在电路和逻辑层面究竟是怎样实现的? +3. 为什么我们在 C 语言里向一个特定的内存地址赋值(比如 *GPIO_ODR = 0x01),LED 灯就会亮,或者串口就会发出数据?在 CPU 眼里,内存条(RAM)和外设寄存器到底有什么区别? + +在学生阶段的开发中,我们往往使用arduino、stm32等等所谓生态较好的设备,也就是说我们见到其实是一个经过抽象的软件库,对于我们来说, +基于库的编程实际上已经和纯软件的编程没有特别大的差别,需要注意的往往是如何协调性能而不是如何bringup一个Baremetal的开发环境。 +但我想,深入到软硬件协同开发的这个视角,是完全有必要的。 + +## Renode的基本使用方式 + +本节介绍 Renode 的安装以及文件结构。 + +### 安装与运行(Windows) + +对于 Windows 用户,Renode 推荐使用其 **Portable (.NET version)** 版本。 + +- **为什么推荐?** 传统的安装版通常依赖于系统安装的 .NET 环境,有时会因为版本不匹配导致各种玄学问题。而 `Portable` 版本包含了独立的 `.NET` 运行环境,解压缩即用,不会污染系统,且更容易备份和移动。(*并且改源码也会更随便*) +- **获取方式:** 前往 [Renode GitHub Releases](https://github.com/renode/renode/releases),下载文件名形如 `renode-x.y.z.dotnet-portable.zip` 的压缩包。 +- **运行:** 解压后,直接运行 `renode.exe` 即可启动控制台(Monitor)。 + +### 揭秘 Renode 的文件结构 + +Renode 的仿真过程通常由三种核心文件驱动:以 `stm32f4_discovery` 为例,我们可以清晰地看到它们的职责分工。 + +![stm32f4_discovery](./assets/2602021659.png) + +#### 1. `.resc` (Renode Script) —— 仿真脚本 + +`.resc` 文件是仿真的入口。它的作用像是一份“剧本”,告诉 Renode 应该搭建什么样的舞台,选用哪些演员(硬件),以及什么时候开始表演。 + +如果你去查阅 Renode 内置的 `stm32f4_discovery.resc`,你会发现其精简后的逻辑如下: + +```renode +# 1. 创建一台机器(Machine) +mach create "stm32f4_discovery" + +# 2. 加载硬件描述文件(.repl) +machine LoadPlatformDescription @platforms/boards/stm32f4_discovery-kit.repl + +# 3. 设置启动属性或外设查看窗口 +showAnalyzer sysbus.uart2 + +# 4. 加载编译好的固件(ELF 或 BIN) +sysbus LoadELF @xxxxxx.elf +``` + +**总结:** `.resc` 负责环境搭建(创建机器、设置连接、加载固件)。 + +#### 2. `.repl` (Renode Platform) —— 硬件描述 + +`.repl` 文件定义了真实的硬件长什么样。比如 CPU 是什么型号、Flash 在哪里、UART 的寄存器地址是多少。 + +它描述的是**内存映射(Memory Map)**。在 `stm32f4_discovery.repl` 中,你会看到类似的定义: + +```renode +// 定义内存 +flash: Memory.MappedMemory @ sysbus 0x08000000 + size: 0x100000 + +sram: Memory.MappedMemory @ sysbus 0x20000000 + size: 0x20000 + +// 定义外设并将其挂载到系统总线(sysbus)的特定地址 +uart2: UART.STM32_UART @ sysbus 0x40004400 + IRQ -> nvic@38 +``` + +这种声明式的定义极其强大:你甚至不需要懂 C 语言或硬件设计,只要照着芯片手册(Datasheet)把地址和中断号填进去,就能“凭空”造出一块开发板。 + +这种明明白白的系统内部总线视角正是单纯调库实现功能所缺乏的视角。 + +#### 3. 固件文件 (`.elf` / `.bin`) —— 运行代码 + +这是你使用 Keil、STM32CubeIDE 或 VS Code 编译出来的可执行文件。Renode 会模拟 CPU 执行这些二进制指令。 + +理解了上述结构,你就会发现 Renode 的工作路径非常清晰: + +1. **开发者编写代码**并编译生成 `.elf`。 +2. **`.repl` 文件**告诉 Renode 硬件是什么样的(地址映射等)。 +3. **`.resc` 脚本**把硬件组装好,把 `.elf` 塞进 Flash 模拟运行。 + +这种“软硬分离”的设计,使得我们可以通过修改 `.repl` 在一秒钟内改变硬件配置(比如把 128KB 的 RAM 改成 512KB),而无需像传统仿真器(如qemu)那样重新编译仿真引擎。 + +### 实际来运行一个例子:Microsemi Mi-V (RISC-V) + +为了直观感受 Renode 的工作流程,我们以官方文档中的 **Microsemi Mi-V**(基于 RISC-V 架构) demo 为例。这个例子展示了如何从零开始带起一个运行 LiteOS 的仿真环境。 + +> **注:** 本节参考自 [Renode 官方教程 - Mi-V example](https://renode.readthedocs.io/en/latest/tutorials/miv-example.html)。 + +#### 1. 启动并加载脚本 + +在启动 Renode 后,你会看到一个名为 **Monitor** 的黑色控制台。这是你与仿真世界互动的主要窗口。 + +![Renode-Monitor](./assets/2602021644.png) + +在 Monitor 中输入以下命令来加载预定义的脚本: + +```renode +include @scripts/single-node/miv.resc +``` + +- `include` (或简写为 `i`):告诉 Renode 执行一个脚本。 +- `@`:在 Renode 路径语法中,`@` 代表路径的起点。 +- `scripts/single-node/miv.resc`:这是 Renode 自带的脚本。它会按照上一节提到的逻辑:创建机器 -> 加载 .repl 描述 -> 注入官方提供的 .elf 固件。 + +#### 2. 观察输出 + +![Renode-MIV](./assets/2602021646.png) + +如果你执行成功,Renode 会自动弹出一个 **UART Analyzer** 窗口。这个窗口模拟了真实开发板的串口调试助手,所有的 printf 输出都会在这里显示。 + +#### 3. 控制仿真 + +加载完成后,仿真默认是暂停状态。你需要在 Monitor 中输入: + +```renode +start +``` + +此时,你会看到 UART 窗口开始滚动输出 zephyr 的启动日志。 +你可以随时输入 `pause` 暂停世界,或者输入 `logLevel 0`(即 Debug 级)来在日志窗口看到更详细的运行信息。 + +![Sim](./assets/2602021649.png) + +#### 4. 结束仿真 + +要想结束仿真,输入: + +```renode +quit +``` + +如果只是想清理当前machine而不结束monitor,输入: + +```renode +Clear +``` diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021644.png" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021644.png" new file mode 100644 index 0000000..6af7e07 Binary files /dev/null and "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021644.png" differ diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021646.png" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021646.png" new file mode 100644 index 0000000..bbdac27 Binary files /dev/null and "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021646.png" differ diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021649.png" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021649.png" new file mode 100644 index 0000000..2ff5888 Binary files /dev/null and "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021649.png" differ diff --git "a/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021659.png" "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021659.png" new file mode 100644 index 0000000..0d74d03 Binary files /dev/null and "b/\350\275\257\344\273\266(Software)/Renode\344\273\277\347\234\237/assets/2602021659.png" differ