运动传感器仪表盘
motion 姿态采样、气压高度、haptics 反馈和 Chart。
演示 motion 姿态与气压高度采样、haptics 反馈,以及 Chart 展示姿态角。
#预期效果
运行后会出现运动传感器仪表盘,姿态采样、图表和触觉反馈按钮都有明确状态。
#完整示例
已复制
import math
import time
import appui
import haptics
import motion
state = appui.State(
status="点击采样读取传感器",
roll=0.0,
pitch=0.0,
yaw=0.0,
gravity="--",
rotation="--",
altitude="--",
samples=[
{"axis": "roll", "value": 0},
{"axis": "pitch", "value": 0},
{"axis": "yaw", "value": 0},
],
)
def degrees(value):
return float(value or 0) * 180.0 / math.pi
def format_vec(data):
if not data:
return "--"
return f'x {data.get("x", 0):.2f}, y {data.get("y", 0):.2f}, z {data.get("z", 0):.2f}'
def sample_motion():
if not motion.is_available():
state.status = "当前设备不支持运动传感器"
haptics.notification("error")
return
motion.start_updates(interval=1 / 30)
time.sleep(0.15)
attitude = motion.get_attitude() or {}
gravity = motion.get_gravity()
rotation = motion.get_rotation_rate()
motion.stop_updates()
roll = degrees(attitude.get("roll", 0))
pitch = degrees(attitude.get("pitch", 0))
yaw = degrees(attitude.get("yaw", 0))
state.batch_update(
status="采样完成",
roll=roll,
pitch=pitch,
yaw=yaw,
gravity=format_vec(gravity),
rotation=format_vec(rotation),
samples=[
{"axis": "roll", "value": roll},
{"axis": "pitch", "value": pitch},
{"axis": "yaw", "value": yaw},
],
)
haptics.selection()
def sample_altitude():
motion.start_altimeter()
time.sleep(0.2)
alt = motion.get_altitude()
motion.stop_altimeter()
if not alt:
state.altitude = "未读取到气压高度"
haptics.notification("warning")
return
state.altitude = f'{alt.get("relative_altitude", 0):.2f} m / {alt.get("pressure", 0):.2f} kPa'
haptics.notification("success")
def body():
return appui.NavigationStack(
appui.List(
[
appui.Section(
[
appui.LabeledContent("状态", value=state.status),
appui.Button("采样姿态", action=sample_motion)
.button_style("bordered_prominent"),
appui.Button("采样气压高度", action=sample_altitude),
],
header="采样",
),
appui.Section(
[
appui.LabeledContent("Roll", value=f"{state.roll:.1f}°"),
appui.LabeledContent("Pitch", value=f"{state.pitch:.1f}°"),
appui.LabeledContent("Yaw", value=f"{state.yaw:.1f}°"),
appui.LabeledContent("重力", value=state.gravity),
appui.LabeledContent("旋转", value=state.rotation),
appui.LabeledContent("气压高度", value=state.altitude),
],
header="读数",
),
appui.Section(
[
appui.Chart(
state.samples,
x="axis",
y="value",
type="bar",
color="systemTeal",
)
.frame(height=220),
],
header="姿态角",
),
]
).navigation_title("运动")
)
appui.run(body, state=state, presentation="sheet")
#关键技巧
- 先用
motion.start_updates()启动采样,读get_attitude()等,再尽快motion.stop_updates(),避免长时间占用传感器;需要控制采样率时可像示例一样传interval=1 / 30。 - 气压用
start_altimeter/get_altitude/stop_altimeter。 - 图表数据用
State.batch_update一次写回;反馈用hapticsAPI。