@page "/motion/odometry" @rendermode InteractiveWebAssemblyNoPrerender @implements IAsyncDisposable @using Microsoft.AspNetCore.SignalR.Client @using RobotNet10.RobotApp.Client.Clients @using RobotNet10.RobotApp.Client.Shared.Motion @using MudBlazor Odometry (XLOC) @* Header *@
Odometry → XLOC OdometryService → XlocIntegrationService · ~10 Hz
@(OdometryHubClient.IsConnected ? "Connected" : "Disconnected")
@if (!OdometryHubClient.IsConnected) { Đang kết nối tới hub odometry... } @if (lastOdom != null) { @* Meta: frame_id, child_frame_id, stamp *@ Header @lastOdom.FrameId @lastOdom.ChildFrameId @lastOdom.Timestamp.ToString("HH:mm:ss.fff") @* Pose: Position + Orientation *@ Position (m) Orientation (yaw °) Q: (@Format(lastOdom.OrientationX), @Format(lastOdom.OrientationY), @Format(lastOdom.OrientationZ), @Format(lastOdom.OrientationW)) @* Twist: Linear + Angular *@ Linear velocity (m/s) Angular velocity (rad/s) pose_position · pose_orientation · twist_linear · twist_angular → ToXlocOdometry() } else if (OdometryHubClient.IsConnected) { Chưa nhận dữ liệu. Đang chờ broadcast từ server. }
@code { [Inject] private OdometryHubClient OdometryHubClient { get; set; } = null!; private OdometryDto? lastOdom; protected override async Task OnInitializedAsync() { OdometryHubClient.OdometryReceived += OnOdometryReceived; OdometryHubClient.ConnectionStateChanged += OnConnectionStateChanged; await OdometryHubClient.StartAsync(); if (OdometryHubClient.IsConnected) { lastOdom = await OdometryHubClient.GetCurrentOdometryAsync(); } } private void OnOdometryReceived(OdometryDto dto) { lastOdom = dto; InvokeAsync(StateHasChanged); } private void OnConnectionStateChanged(HubConnectionState _) { InvokeAsync(StateHasChanged); } private double YawDegrees { get { if (lastOdom == null) return 0; var qw = lastOdom.OrientationW; var qz = lastOdom.OrientationZ; var qx = lastOdom.OrientationX; var qy = lastOdom.OrientationY; var yaw = Math.Atan2(2.0 * (qw * qz + qx * qy), 1.0 - 2.0 * (qy * qy + qz * qz)); return yaw * 180.0 / Math.PI; } } private static string Format(double value) => value.ToString("F4"); private static string FormatDegrees(double value) => value.ToString("F2") + " °"; public async ValueTask DisposeAsync() { OdometryHubClient.OdometryReceived -= OnOdometryReceived; OdometryHubClient.ConnectionStateChanged -= OnConnectionStateChanged; await OdometryHubClient.DisposeAsync(); } }