Initial commit

This commit is contained in:
2026-07-03 16:31:37 +07:00
commit 899c7c637d
1939 changed files with 641750 additions and 0 deletions

View File

@@ -0,0 +1,376 @@
# XLOC Manual Control API Guide
Now you have **FULL MANUAL CONTROL** over XLOC SLAM operations! Control via:
1. C# Service Methods
2. REST API Endpoints
3. SignalR Hub Methods
---
## 1. C# Service Methods (Direct)
Inject `XlocIntegrationService` into your service:
```csharp
public class MyNavigationService
{
private readonly XlocIntegrationService _xloc;
public MyNavigationService(XlocIntegrationService xloc)
{
_xloc = xloc;
}
public void StartLocalizationWithMap()
{
// Activate map
if (_xloc.ActivateMap("/maps/factory_floor.pbstream"))
{
// Start localization
_xloc.StartLocalization();
}
}
public void BeginMapping()
{
_xloc.StartMapping();
}
public void SaveAndStopMapping()
{
_xloc.StopMapping("/maps/new_map.pbstream");
}
}
```
---
## 2. REST API Endpoints
### Activate Map
```bash
curl -X POST "https://localhost:7002/api/xloc/activate-map?mapPath=/maps/factory.pbstream"
```
Response:
```json
{
"success": true,
"message": "Map activated"
}
```
### Start Mapping
```bash
dotnet build
# Restart app
pkill -f dotnet
./run-quiet.sh
# Test mapping
curl -k -X POST https://127.0.0.1:7002/api/motion/ps5/enable
curl -k -X POST https://localhost:7002/api/xloc/mapping/start
# ... di chuyển robot ...
```
### Stop Mapping
```bash
curl -k -X POST https://localhost:7002/api/xloc/mapping/stop \
-H "Content-Type: application/json" \
-d '{"map_file_path": "test14"}'
```
### Active Map
```bash
curl -k -X POST https://localhost:7002/api/xloc/map/activate \
-H "Content-Type: application/json" \
-d '{"map_file_path": "test10"}'
```
### Start Localization
```bash
curl -k -X POST https://localhost:7002/api/xloc/localization/start
```
### Stop Localization
```bash
curl -k -X POST https://localhost:7002/api/xloc/localization/stop
```
### Reset SLAM State
```bash
# Reset SLAM error state (automatically called before start mapping/localization)
# Useful if you manually need to clear previous trajectory state
curl -k -X POST https://localhost:7002/api/xloc/slam/reset
```
**Note:** `StartMapping()` and `StartLocalization()` now automatically call reset before starting, so you typically don't need to call this manually.
### Stop Mapping & Save
**Option 1: Manual (will crash, but map is saved)**
```bash
# Save with timestamp
MAP_NAME="map_$(date +%Y%m%d_%H%M%S).pbstream"
curl -k -X POST "https://localhost:7002/api/xloc/stop-mapping?savePath=/home/robotics/sonvh/RobotNet10/srcs/RobotNet10/RobotApp/RobotNet10.RobotApp/Xloc/map/$MAP_NAME"
# Or save with custom name (MUST include .pbstream extension!)
curl -k -X POST "https://localhost:7002/api/xloc/stop-mapping?savePath=/home/robotics/sonvh/RobotNet10/srcs/RobotNet10/RobotApp/RobotNet10.RobotApp/Xloc/map/my_map.pbstream"
cd Xloc
./map-and-save.sh my_office_map.pbstream
# Note: Application will crash due to XLOC Cairo bug, but map is saved successfully
# Restart with: ./run-quiet.sh
```
**Option 2: Automated script (recommended)**
```bash
# Use automated script that handles crash and restart
cd Xloc
./map-and-save.sh my_map.pbstream
# Script will:
# 1. Wait for you to drive robot
# 2. Save map on ENTER
# 3. Handle crash gracefully
# 4. Auto-restart application
```
### Get Current Pose
```bash
curl "https://localhost:7002/api/xloc/pose"
```
Response:
```json
{
"x": 1.234,
"y": 5.678,
"yaw": 1.57,
"yawDegrees": 90.0
}
```
---
## 3. SignalR Hub Methods
### TypeScript/JavaScript Client
```typescript
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("https://localhost:7002/hubs/xloc/pose")
.build();
// Subscribe to pose updates (realtime streaming)
connection.on("ReceivePose", (pose) => {
console.log(`Position: (${pose.x}, ${pose.y}), Heading: ${pose.yawDegrees}°`);
});
await connection.start();
// Control SLAM manually
async function startLocalization() {
const success = await connection.invoke("StartLocalization");
console.log("Localization started:", success);
}
async function activateMap(mapPath: string) {
const success = await connection.invoke("ActivateMap", mapPath);
console.log("Map activated:", success);
}
async function startMapping() {
const success = await connection.invoke("StartMapping");
console.log("Mapping started:", success);
}
async function stopMapping(savePath: string) {
const success = await connection.invoke("StopMapping", savePath);
console.log("Map saved:", success);
}
async function getCurrentPose() {
const pose = await connection.invoke("GetCurrentPose2D");
console.log("Current pose:", pose);
// { x: 1.234, y: 5.678, yaw: 1.57, yawDegrees: 90.0 }
}
```
### React Example
```tsx
import { HubConnectionBuilder } from '@microsoft/signalr';
import { useState, useEffect } from 'react';
export function XlocControl() {
const [connection, setConnection] = useState(null);
const [pose, setPose] = useState(null);
useEffect(() => {
const conn = new HubConnectionBuilder()
.withUrl("https://localhost:7002/hubs/xloc/pose")
.build();
conn.on("ReceivePose", (data) => {
setPose(data);
});
conn.start();
setConnection(conn);
return () => conn.stop();
}, []);
const handleStartLocalization = async () => {
const result = await connection.invoke("StartLocalization");
console.log("Started:", result);
};
const handleStartMapping = async () => {
const result = await connection.invoke("StartMapping");
console.log("Mapping started:", result);
};
return (
<div>
<h2>XLOC Control Panel</h2>
{pose && (
<div>
<p>X: {pose.x.toFixed(2)}m</p>
<p>Y: {pose.y.toFixed(2)}m</p>
<p>Heading: {pose.yawDegrees.toFixed(1)}°</p>
</div>
)}
<button onClick={handleStartLocalization}>
Start Localization
</button>
<button onClick={handleStartMapping}>
Start Mapping
</button>
</div>
);
}
```
---
## Typical Workflows
### Workflow 1: Localization (Using Existing Map)
```bash
# 1. Activate map
POST /api/xloc/activate-map?mapPath=/maps/factory.pbstream
# 2. Start localization
POST /api/xloc/start-localization
# 3. Robot is now localizing!
# Pose updates stream automatically via SignalR
# 4. When done
POST /api/xloc/stop-localization
```
### Workflow 2: Mapping (Create New Map)
```bash
# 1. Start mapping
POST /api/xloc/start-mapping
# 2. Drive robot around
# Map is being created in realtime
# 3. Save and stop
POST /api/xloc/stop-mapping?savePath=/maps/new_building.pbstream
```
---
## Available Methods in All Interfaces
| Method | XlocIntegrationService | REST API | SignalR Hub |
|--------|----------------------|----------|-------------|
| ActivateMap | ✅ `ActivateMap(mapPath)` | ✅ `POST /api/xloc/activate-map` | ✅ `connection.invoke("ActivateMap", mapPath)` |
| StartLocalization | ✅ `StartLocalization()` | ✅ `POST /api/xloc/start-localization` | ✅ `connection.invoke("StartLocalization")` |
| StopLocalization | ✅ `StopLocalization()` | ✅ `POST /api/xloc/stop-localization` | ✅ `connection.invoke("StopLocalization")` |
| StartMapping | ✅ `StartMapping()` | ✅ `POST /api/xloc/start-mapping` | ✅ `connection.invoke("StartMapping")` |
| StopMapping | ✅ `StopMapping(savePath)` | ✅ `POST /api/xloc/stop-mapping` | ✅ `connection.invoke("StopMapping", savePath)` |
| GetCurrentPose2D | ✅ `GetCurrentPose2D()` | ✅ `GET /api/xloc/pose` | ✅ `connection.invoke("GetCurrentPose2D")` |
---
## Important Notes
**No Auto-Start**: SLAM does NOT start automatically anymore!
**Manual Control Only**: You must explicitly call start methods
**Sensor Data Streaming**: Continues automatically at 20Hz (Odom + IMU)
**Pose Streaming**: Broadcasts via SignalR at 5Hz when SLAM is running
## Configuration
```json
{
"Xloc": {
"Integration": {
"Enabled": true,
"Mode": "Mapping", // Ignored - now manual control
"UpdateRateHz": 20,
"MapFilePath": "", // Ignored - call ActivateMap() manually
"SaveMapFilePath": "/tmp/xloc_map.pbstream"
}
}
}
```
Note: `Mode` and `MapFilePath` in config are now ignored. Use manual control methods instead!
---
## Troubleshooting
### Cannot start mapping after stop & save
**Problem:** After stopping localization or mapping, `StartMapping()` fails.
**Root Cause:** XLOC library retains the finished trajectory state. Starting a new mapping/localization session requires clearing this state.
**Solution (Automatic):** `StartMapping()` and `StartLocalization()` now automatically call `ResetSlamError()` before starting, which clears the previous trajectory state.
**Manual Reset (if needed):**
```bash
# If automatic reset doesn't work, manually reset SLAM state
curl -k -X POST https://localhost:7002/api/xloc/slam/reset
# Then try starting mapping again
curl -k -X POST https://localhost:7002/api/xloc/mapping/start
```
**What the fix does:**
- Clears finished trajectory (trajectory ID from previous session)
- Resets SLAM error state to Idle
- Prepares XLOC library for new mapping/localization session
### General Workflow After Fix
```bash
# 1. Stop previous session (if any)
curl -k -X POST https://localhost:7002/api/xloc/localization/stop
# 2. Start mapping (automatic reset happens internally)
curl -k -X POST https://localhost:7002/api/xloc/mapping/start
# 3. Drive robot around...
# 4. Stop and save
curl -k -X POST https://localhost:7002/api/xloc/mapping/stop \
-H "Content-Type: application/json" \
-d '{"map_file_path": "my_new_map"}'
# 5. Start mapping again (works now!)
curl -k -X POST https://localhost:7002/api/xloc/mapping/start
```