跳转至主要内容

07. 基座与安装——游乐场

交互式控制 蒙特变换 该设备的功能,并演示如何 configure.basis, configure.preset und configure.mount 在协议层面上协同工作。将保持一个固定的水平底层,以便交互重点仍集中在 configure 命令上。

您将学到:

  • 设置一个 基底置换 ("XZY" → 应用框架(Y轴朝上))
  • 选择一个 预设 (arm_front) 并理解其配置内容
  • 在运行时使用旋转四元数覆盖挂载(通过键盘控制)
  • 互斥性法则: mount und preset 不能共同位于同一块的 设备配置 vorkommen
  • 一次性 configure-语义:每次按键都会发送且仅发送一条 configure 消息
  • (C++ Glaze) 使用……对相互排斥的字段进行建模 std::optional

流程​

  1. 对于第一条消息:请发送该 会话概况, configure.basis: "XZY" und configure.preset: arm_front. 开始为坚实的地基做准备 set_cursor_force 发送。
  2. 每次时钟脉冲:读取光标Y值, force_y = max(0, (floor_pos - y) * stiffness) 计算并发送。
  3. 当用户按下挂载轮换按钮时,请设置 pending_configure = true.
  4. 在下一次 tick 时,请创建一个 configure.mount-使用一个变换的块,其 rotation 是一个单位四元数(由当前俯仰角和偏航角按 Z-X 顺序组合而成)。请 preset weg——这两者在协议层面上是相互排斥的。
  5. 重置按钮(R) 取消覆盖;下一个 configure 指令将再次使用 preset 返回。

参数​

名称标准Zweck
BASIS"XZY"轴排列——Y轴朝上的应用框架
DEVICE_PRESET / DEVICE_CONFIG_PRESET"arm_front"命名预设——源自设备底座
FLOOR_POS_Y0.0 m固定地面平面(应用-Y)
STIFFNESS1000 不适用土壤的弹性常数
MOUNT_STEP_DEG10°按键旋转
PRINT_EVERY_MS200遥测数据限流

控制​

口味Aktion
W / S沿设备+X轴旋转±10微米(俯仰角)
A / D沿设备的+Z轴旋转±10°(偏航)
R重置音色——返回预设
H显示控制面板
Q结束
mount und preset 相互排斥

该服务拒绝封锁 设备配置 ab,其中包含这两者。一旦用户覆盖了挂载点,本教程就会 preset 在后续的每个 configure 语句中都会被省略。按下 R 将 preset 在接下来的 configure 指令中重新启用,并 mount 被驳回。

不同的输入模式

C++ 版本会在后台的 stdin 线程中读取基于行的输入(输入每个字母后按 ENTER 键)。Python 则使用该包 keyboard 用于在异步主循环中进行实时按键检测——无需按 ENTER 键。相同的按键,相同的命令。

已读取的状态字段​

Aus data.inverse3[i].state:

  • cursor_position.y — vec3, 用于计算地面穿透深度
  • current_cursor_force — 将作为遥测数据上报

发送 / 接收​

所有变体的有效载荷结构都相同;值得关注的是,各变体在处理相互排斥的分支时所表现出的差异 mount / preset 如何构建,以及输入线程如何向 WebSocket 线程发送信号。

通过该包实现带实时按键检测的单个异步循环 keyboard. pending_configure 这是一个全局标志,由键盘处理程序设置,并在每次发生 configure- 已发送该块。

async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)

if first_message:
first_message = False
device_id = data["inverse3"][0]["device_id"]
# Handshake: profile + basis + preset
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": build_configure_block(first_handshake=True),
# -> {"basis": {"permutation": "XZY"},
# "preset": {"preset": "arm_front"}}
}],
}
else:
handle_key_inputs() # may set pending_configure = True (classic, not shown)

y = data["inverse3"][0]["state"]["cursor_position"]["y"]
force_y = 0.0 if y > FLOOR_POS_Y else (FLOOR_POS_Y - y) * STIFFNESS

entry = {
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": force_y, "z": 0.0}}},
}
if pending_configure:
entry["configure"] = build_configure_block(first_handshake=False)
# -> {"mount": {...}} OR {"preset": {...}} (never both)
pending_configure = False

request_msg = {"inverse3": [entry]}

await websocket.send(json.dumps(request_msg))
包含在 SDK 安装程序中

教程 07 也已随 SDK 一起安装在本地——可在以下位置找到: tutorials/07-haply-inverse-basis-and-mount/ 位于该服务的安装目录中。

来源: Python·C++·C++ Glaze

相关: 基底置换 · 安装与工作区 · 设备配置 · 控制命令 (set_cursor_force) · 类型(转换) · 教程 04(Hello Floor)