3. PolyScope界面扩展基础
URCap 的界面扩展本质上是一个运行在 PolyScope 内置浏览器环境中的 Web 应用。PolyScope 基于 Qt WebEngine(Chromium 内核)渲染 URCap 的 HTML 页面,因此开发者可以用标准的 HTML 描述结构、CSS 描述样式、JavaScript 描述交互逻辑。但与传统 Web 应用不同,这个页面运行在机器人示教器内部,必须通过 URCap 提供的 getRobotAPI() 接口与机器人控制器通信,才能读写程序变量、控制 I/O、响应安装节点配置等。理解“页面渲染层”与“机器人数据层”之间的桥接机制,是本节的核心。
一、URCap 界面扩展的三层结构
一个可交互的 URCap 界面由三层组成。最上层是 视图层,由 HTML 与 CSS 构成,负责按钮、输入框、标签等控件的布局与外观;中间层是 逻辑层,由 JavaScript 构成,负责监听用户操作、校验输入、调用 API;最下层是 通信层,由 URCap 的 RobotAPI 对象构成,负责把 JavaScript 的调用翻译成对控制器数据的读写。三层之间通过明确的接口传递数据,而不是直接互相访问。
在 URCap 的 contribution 目录中,通常会有 program 与 installation 两个子目录,分别对应程序节点界面和安装节点界面。每个目录下放置 *.html、*.css、*.js 文件,并在 urcap.xml 中通过 <webPage> 标签声明入口文件。PolyScope 加载 URCap 时,会读取该声明并把对应 HTML 渲染到示教器屏幕的指定区域。
二、HTML 与 CSS:构建可用的控件布局
URCap 的 HTML 页面不需要完整的 <html> 文档结构,通常只写一个容器 <div> 即可,因为 PolyScope 会把它嵌入到自己的页面框架中。一个典型的程序节点界面包含一个数值输入框和一个确认按钮:
<div id="urcap-root">
<label for="speedInput">目标速度 (mm/s)</label>
<input id="speedInput" type="number" min="1" max="500" value="100">
<button id="applyBtn">应用</button>
<p id="statusText">等待设置</p>
</div>
CSS 方面,PolyScope 的显示区域有限,示教器屏幕分辨率通常为 1280×800 或更低,因此控件尺寸要足够大,便于手指点按。建议按钮最小高度 44px,输入框字号不小于 16px,避免使用过小的字体或密集的布局。颜色上应与 PolyScope 的深色主题保持协调,通常使用浅色背景配深色文字,或直接继承 PolyScope 的样式变量。
#urcap-root { padding: 16px; font-size: 16px; }
#speedInput { width: 160px; height: 40px; font-size: 16px; }
#applyBtn { height: 44px; padding: 0 24px; background: #2f7fd1; color: #fff; border: none; border-radius: 6px; }
#statusText { margin-top: 12px; color: #555; }
三、JavaScript 与 RobotAPI 的通信机制
PolyScope 在加载 URCap 页面时,会向页面注入一个全局函数 getRobotAPI()。调用它返回一个 RobotAPI 对象,该对象提供多个子 API:Program 用于读写程序节点数据,Installation 用于读写安装节点配置,UserInteraction 用于弹出提示或对话框。这些 API 的调用是异步的,返回 Promise,因此需要用 async/await 或 .then() 处理结果。
下面是一个按钮点击后把输入框数值写入程序变量的示例。假设在 URCap 的 XML 中已经声明了一个名为 targetSpeed 的变量:
const api = getRobotAPI();
document.getElementById('applyBtn').addEventListener('click', async () => {
const input = document.getElementById('speedInput');
const value = parseFloat(input.value);
if (isNaN(value) || value < 1 || value > 500) {
document.getElementById('statusText').textContent = '请输入 1~500 之间的数值';
return;
}
try {
await api.Program.setVariable('targetSpeed', value);
document.getElementById('statusText').textContent = '已写入:' + value + ' mm/s';
} catch (err) {
document.getElementById('statusText').textContent = '写入失败:' + err.message;
}
});
这段代码体现了完整的交互闭环:用户输入 → JavaScript 校验 → 调用 API 写入控制器 → 根据返回结果更新界面状态。其中 setVariable 是 Program API 的典型方法,实际名称可能因 URCap SDK 版本不同而略有差异,开发时应以对应版本的 API 文档为准。
async/await、let/const、箭头函数等现代语法。但不要使用 import/export 模块语法,因为页面通常以普通脚本方式加载,模块化需要通过多个 <script> 标签或打包工具处理。四、安装节点与程序节点的通信差异
安装节点界面与程序节点界面的通信方式略有不同。安装节点在 PolyScope 的“安装”选项卡中配置,其数据在程序运行前就已经确定,通常用于设置工具参数、负载、安全配置等。程序节点则在程序执行到该节点时生效,用于动态控制。两者都通过 getRobotAPI() 获取 API,但安装节点更多使用 Installation 子 API,程序节点更多使用 Program 子 API。
一个常见的实践是:在安装节点中让用户输入工具重心坐标,保存到安装配置;在程序节点中读取该配置,结合当前速度计算力矩限制。这种跨节点的数据传递必须通过控制器存储,而不能依赖 JavaScript 全局变量,因为两个页面可能在不同时间加载,全局变量不会保留。
五、调试与常见问题
URCap 界面调试比普通 Web 页面困难,因为无法直接打开浏览器开发者工具。常用的排查手段有三种:一是利用 UserInteraction API 弹出提示框显示中间变量值;二是把关键信息写入 statusText 等页面元素,直接在示教器上观察;三是查看 PolyScope 的日志文件,通常位于控制器文件系统的 /root/.urcaps/ 或 /programs/ 相关目录下。
常见问题包括:getRobotAPI() 返回 undefined,通常是因为页面没有通过 URCap 框架加载,而是被直接当普通网页打开;API 调用报权限错误,通常是因为在 urcap.xml 中没有声明对应的 API 权限;界面不刷新,通常是因为异步调用完成后没有手动更新 DOM。建议在每次 API 调用后都显式更新状态文本,形成“调用—反馈”的可见链路。
setTimeout 分片执行。六、一个可复用的最小交互模板
综合以上内容,可以整理出一个最小可用的 URCap 界面模板,包含输入、校验、写入、反馈四个环节。开发者只需替换变量名和 API 方法,即可快速搭建新的交互界面。模板的核心结构如下表所示。
| 环节 | 实现位置 | 关键代码/方法 | 作用 |
|---|---|---|---|
| 输入 | HTML | <input id="speedInput"> | 接收用户数值 |
| 触发 | JavaScript | addEventListener('click', ...) | 监听按钮点击 |
| 校验 | JavaScript | isNaN / 范围判断 | 拦截非法输入 |
| 写入 | RobotAPI | api.Program.setVariable() | 把数据送到控制器 |
| 反馈 | HTML + JS | statusText.textContent | 显示成功或失败 |
掌握这个模板后,就可以在此基础上扩展更多控件,例如用下拉框选择 I/O 端口、用滑块调节速度百分比、用复选框启用某段逻辑。无论控件如何变化,通信机制始终是“JavaScript 调用 RobotAPI,API 读写控制器数据,界面根据返回结果更新”。理解这条主线,PolyScope 界面扩展就不再是黑盒。