10 KiB
XLOC Manual Control API Guide
Now you have FULL MANUAL CONTROL over XLOC SLAM operations! Control via:
- C# Service Methods
- REST API Endpoints
- SignalR Hub Methods
1. C# Service Methods (Direct)
Inject XlocIntegrationService into your service:
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
curl -X POST "https://localhost:7002/api/xloc/activate-map?mapPath=/maps/factory.pbstream"
Response:
{
"success": true,
"message": "Map activated"
}
Start Mapping
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
curl -k -X POST https://localhost:7002/api/xloc/mapping/stop \
-H "Content-Type: application/json" \
-d '{"map_file_path": "test14"}'
Active Map
curl -k -X POST https://localhost:7002/api/xloc/map/activate \
-H "Content-Type: application/json" \
-d '{"map_file_path": "test10"}'
Start Localization
curl -k -X POST https://localhost:7002/api/xloc/localization/start
Stop Localization
curl -k -X POST https://localhost:7002/api/xloc/localization/stop
Reset SLAM State
# 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)
# 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)
# 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
curl "https://localhost:7002/api/xloc/pose"
Response:
{
"x": 1.234,
"y": 5.678,
"yaw": 1.57,
"yawDegrees": 90.0
}
3. SignalR Hub Methods
TypeScript/JavaScript Client
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
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)
# 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)
# 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
{
"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):
# 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
# 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