cap_lua 与 Lua 综述
源码:cap_lua.ccomponents/claw_capabilities/cap_lua/src/cap_lua.c · 头文件:cap_lua.hcomponents/claw_capabilities/cap_lua/include/cap_lua.h
Lua 在 ESP-Claw 中的定位
Section titled “Lua 在 ESP-Claw 中的定位”ESP-Claw 将 Lua 作为设备端「可编程自动化」的首选语言。它在系统中扮演三个角色:
1. LLM 可编程的执行层
Section titled “1. LLM 可编程的执行层”LLM 可以通过文件工具写入 Lua 脚本(write_file),然后执行(lua_run_script)。Lua 是 LLM 与硬件外设之间的桥梁:LLM 用自然语言的逻辑生成代码,Lua 负责实际执行 GPIO 操作、屏幕绘制、音频播放等。
2. 自动化动作的载体
Section titled “2. 自动化动作的载体”claw_event_router 支持 run_script 动作,允许事件规则在不经过 LLM 的情况下直接触发 Lua 脚本:
这让设备具备完全本地、低延迟的自动化响应能力,不依赖网络和 LLM 推理。
3. 快速原型与扩展接口
Section titled “3. 快速原型与扩展接口”对于不熟悉 C 开发的用户,Lua 脚本提供了一种无需重新编译固件即可扩展设备行为的方式。通过 lua_module_* / lua_driver_* 机制注册的原生模块,可以将任意外设能力以简洁的 Lua API 暴露出来。
Lua 运行时概述
Section titled “Lua 运行时概述”ESP-Claw 使用 Lua 解释器,通过 cap_lua_runtime_* 系列函数初始化和执行脚本。运行时在 cap_lua_group_init 中初始化,锁定模块注册后启动。
脚本路径管理
Section titled “脚本路径管理”cap_lua 的可写运行时脚本需位于 Script 基目录(Script Base Dir)下。edge_agent 中 Script Base Dir 默认为 /fatfs/scripts/(应用可通过 cap_lua_set_base_dir 修改)。Skill 自带脚本是只读资源,允许以 /fatfs/skills/<skill_id>/scripts/... 形式执行。
path必须是.lua文件。path可用两种形式:- 受管相对路径:如
hello.lua或builtin/test/hello.lua(会自动拼到${base_dir}下,且不能包含..)。 - Skill 本地绝对路径:如
{CUR_SKILL_DIR}/scripts/hello.lua,前提是活动 Skill 文档明确提供该脚本。该路径会展开到/fatfs/skills/<skill_id>/scripts/...,必须位于 Skill 根目录下,且不能包含..。
- 受管相对路径:如
- 使用文件工具发现和读取脚本:
list_dir {"keyword":"scripts/"}与read_file {"path":"scripts/hello.lua"}。
cap_lua_register_module 只能在 cap_lua_group_init 调用之前执行。初始化完成后,s_module_registration_locked = true,之后的注册调用返回 ESP_ERR_INVALID_STATE。这确保运行时启动时模块集合已确定。
cap_lua 工具集
Section titled “cap_lua 工具集”cap_lua 当前注册了六个 Callable:
| 工具 ID | 功能 |
|---|---|
lua_run_script | 同步执行脚本,等待结果返回 |
lua_run_script_async | 异步提交脚本,立即返回 job_id |
lua_list_async_jobs | 列举异步任务(按状态过滤) |
lua_get_async_job | 查询特定异步任务的状态和输出(支持按 job_id 或 name) |
lua_stop_async_job | 停止单个异步任务(按 job_id 或 name) |
lua_stop_all_async_jobs | 批量停止异步任务(可按 exclusive 分组过滤) |
同步执行 vs. 异步执行
Section titled “同步执行 vs. 异步执行”| 方式 | 适用场景 | 超时 | 返回值 |
|---|---|---|---|
lua_run_script | 快速计算、状态读取 | 可设 timeout_ms | 脚本输出字符串 |
lua_run_script_async | 长耗时操作(动画、等待传感器) | timeout_ms=0 表示持续运行直到被停止(默认) | job_id |
lua_run_script_async 支持 name、exclusive、replace 三个控制字段:
name:给任务一个逻辑名,便于后续lua_get_async_job/lua_stop_async_job按名称操作。exclusive:互斥分组(例如"display"),同组常用于“单槽位”资源。replace: true:当同名或同exclusive组已有活动任务时,尝试抢占并替换旧任务。
典型流程:
脚本参数传递
Section titled “脚本参数传递”脚本执行时可传入 JSON 对象或数组作为参数(args 字段),在脚本内通过 args 全局变量访问:
当 lua_run_script / lua_run_script_async 由 Agent 在 IM 会话中触发时,如果工具调用里没有显式提供 args.channel、args.chat_id、args.session_id,运行时会自动把当前会话上下文合并进 args。
这让脚本可以直接读取会话信息(例如回消息)而不必每次均指定。
使用文件工具编写脚本
Section titled “使用文件工具编写脚本”使用 write_file 在文件能力的基目录下创建或覆盖 Lua 脚本。随后用 lua_run_script 执行同一脚本时去掉开头的 scripts/,例如 {"path":"hello.lua"}。
运行时限制与稳定性
Section titled “运行时限制与稳定性”- Lua 超时检测使用指令级 Hook(固定步数触发)+ 墙钟超时,超时后抛出
execution timed out。 - Hook 回调内会主动
taskYIELD(),避免紧密循环长期占用 CPU 导致任务看门狗误触发。 - JSON
args里的“整数值”会尽量以 Lua 整数类型进入脚本,减少 GPIO/像素坐标等参数的类型歧义。
C 语言调用接口
Section titled “C 语言调用接口”除工具调用外,cap_lua 也提供 C 函数接口,供应用代码直接调用:
异步任务状态机
Section titled “异步任务状态机”异步任务有以下状态:
lua_list_async_jobs 支持按状态过滤:"all" / "queued" / "running" / "done" / "failed" / "timeout" / "stopped"。
与 Skill 的协同
Section titled “与 Skill 的协同”cap_lua Skill 文档会指导模型在停止、替换或停用长期任务前,先用 lua_list_async_jobs / lua_get_async_job 按需检查仍在运行的 Lua 异步任务。