← Xvisio Features and Quick Start
← Xvisio SDK Documentation Home Page
This section mainly introduces the VSLAM function and how to quick start a VSLAM programming by using XVSDK.
Xvisio SLAM supports two modes: MIX mode (parts of the SLAM algorithm run on the Xvisio device side, and the others run on the host side), and Edge mode (the SLAM algorithm runs entirely on the device side).
User can select and switch modes freely according to the scenarios. Generally, most of the scenarios are suitable for mix mode, and edge mode can be used in some CPU environments with weak capabilities.
VSLAM is centered on the IMU of Xvisio device. After SLAM starting, a VSLAM coordinate system will be established which based on the device's gravity direction. The origin of the coordinate system is on IMU when VSLAM starts each time. The value of x,y,z is 0 when VSLAM starts. Pitch/yaw/roll represents the rotation of IMU device.
Start the device horizontally:
Tilt the device to start:
Xvisio VSLAM coordinate is default of right-hand. X-axis is in the right positive direction, Y-axis is in the downward positive direction, and the Z-axis is in the forward positive direction. The schematic diagram is shown as follows:
6DOF Pose supports 3 formats (Eulerian angle, rotation matrix and quaternion) to express rotation.The 6DOF structure is shown as below:
struct Pose : public details::PosePred_<double> {
Pose();
/**
* @brief Construct a pose with a translation, rotation, timestamps and confidence.
*/
Pose(Vector3d const& translation, Matrix3d const& rotation,
double hostTimestamp = std::numeric_limits<double>::infinity(), std::int64_t edgeTimestamp = (std::numeric_limits<std::int64_t>::min)(), double c=0.);
/**
* @brief Prediction of the pose based on angular and linear velocity and acceleration.
* @param dt amount of prediction (in s)
* @return The predicted (2nd order extrapolation) of the orientation.
*/
Pose prediction(double dt) const;
};
The time base of hostTimestamp is the host side. Start timing (0) from the host side boot.
The time base of deviceTimestamp is the device side. Start timing (0) from device boot.
confidence indicates the trustworthy level of 6DOF. Value 0 means slam lost and value 1 means the highest confidence.
Xvisio VSLAM supports three ways to get 6DOF:
device->slam()->registerCallback( poseCallback );
bool getPose(Pose &pose, double prediction) ;
bool getPoseAt(Pose& pose, double timestamp);
VIO mode does not include map loopclosure. As the odometer increases, the cumulative error will increase. It is default of VIO mode when VSLAM starts. User can use below interfaces to obtain VIO function:
bool start();
bool stop();
int registerCallback(std::function<void (xv::Pose const&)>);
bool unregisterCallback(int callbackId);
bool getPose(Pose &pose, double prediction) ;
Interface calling process is as follows:
There is no need to build a map in advance. Build a map online and detect whether it is closed-loop in the background in real-time. If it is closed-loop, loopclosure optimization will be done. The disadvantage is that the map is only saved in memory and cannot be reused after restarting the device.
The calling interface of online loopclosure is similar to VIO mode except the setting difference. The interfaces used are as follows:
bool start();
bool stop();
bool xv::SlamEx::setEnableOnlineLoopClosure(bool enable);
int registerCallback(std::function<void (xv::Pose const&)>);
bool unregisterCallback(int callbackId);
bool getPose(Pose &pose, double prediction) ;
Interface calling process is as follows:
The following interfaces are mainly used to achieve CSLAM function:
bool start();
bool stop();
bool loadMapAndSwitchToCslam(std::streambuf &mapStream, std::function<void (int)> done_callback, std::function<void (float)> localized_on_reference_map);
bool saveMapAndSwitchToCslam(std::streambuf &mapStream, std::function<void (int, int)> done_callback, std::function<void (float)> localized_on_reference_map);
Steps to Build Map:
To build a good map, firstly you should consider how to use the map. The map must contain all the viewpoints required by the application. If the final application is in another room, there is no reason to record the map in the current room. Similarly, if the final application displays some virtual objects on the ground, no need to record the other view of the room. The path to be moved by the application should be the final path of the recorded map. In order to ensure a good loop closure, walk on the same path twice: for example, start from a starting point, walk away, return to the starting point, then walk away on the same path again, and then return to the starting point. During the recording process, walking twice on the same path ensures a good overlap between the different recording viewpoints of the loop closure detection. During recording, it is important to avoid moving fast or facing areas with no features.
Sample:
Refer to demo-api.cpp(case 20,case21) for detail code.demo-api
The following is the API call process and schematic diagram, which are introduced according to two usage scenarios:
Sample1. Switch to cslam after mapping
API call process:
device->slam()->saveMapAndSwitchToCslam(mapStream,cslamSavedCallback, cslamLocalizedCallback);
Sample 2:Switch to CSLAM after loading the map
device->slam()->loadMapAndSwitchToCslam(mapStream,cslamSwitchedCallback, cslamLocalizedCallback);
std::shared_ptr<xv::Device> device = nullptr;
auto device_list = xv::getDevices(10., "");
if (device_list.empty())`
{
LOG(LOG_Function,"initDevice faiiled:Timeout for device detection.");
return false;
}
device = device_list.begin()->second;
std::static_pointer_cast<xv::SlamEx>(device->slam())->setEnableOnlineLoopClosure(true);
device->slam()->start(xv::Slam::Mode::Mixed);
device->slam()->start(xv::Slam::Mode::Edge);
int poseId = -1;
poseId = device->slam()->registerCallback([](const xv::Pose& pose){
...
});
double prediction = 0.010;
bool ok = device->slam()->getPose( pose, prediction );
if ( !ok ) {
...//failed.
}
double t = spec_TS;
xv::Pose poseAt;
bool ok = device->slam()->getPoseAt( poseAt, t );
if ( !ok ) {
...//failed.
}
std::filebuf mapStream;`
if (mapStream.open(map_filename, std::ios::binary | std::ios::out | std::ios::trunc) == nullptr) {
std::cout << "open " << map_filename << " failed." << std::endl;
break;
}
device->slam()->saveMapAndSwitchToCslam(mapStream, cslamSavedCallback, cslamLocalizedCallback);
void cslamSavedCallback(int status_of_saved_map, int map_quality)
{
std::cout << " Save map (quality is " << map_quality << "/100) and switch to CSlam:";
switch (status_of_saved_map)
{
case 2: std::cout << " Map well saved. " << std::endl; break;
case -1: std::cout << " Map cannot be saved, an error occured when trying to save it." << std::endl; break;
default: std::cout << " Unrecognized status of saved map " << std::endl; break;
}
mapStream.close();
}
void cslamLocalizedCallback(float percent)
{
static int k = 0;
if (k++ % 100 == 0) {
localized_on_reference_percent = static_cast<int>(percent * 100);
std::cout << "localized: " << localized_on_reference_percent << "%" << std::endl;
}
}
device->slam()->loadMapAndSwitchToCslam(
mapStream,
cslamSwitchedCallback,
cslamLocalizedCallback
);
void cslamSwitchedCallback(int map_quality)
{
std::cout << " map (quality is " << map_quality << "/100) and switch to CSlam:";
mapStream.close();
}
void cslamLocalizedCallback(float percent)
{
static int k = 0;
if (k++ % 100 == 0) {
localized_on_reference_percent = static_cast<int>(percent * 100);
std::cout << "localized: " << localized_on_reference_percent << "%" << std::endl;
}
}
device->slam()->unregisterCallback(poseId);
device->slam()->stop();
← Xvisio Features and Quick Start
← Xvisio SDK Documentation Home Page