Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 45 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
# Augmenta Client C++ SDK

The goal of this library is to make consuming the stream output of an Augmenta server as easy as possible. As of right now this only refers to the data emitted through websocket by the Websocket Output node, but other network protocols might be added later on.
The goal of this library is to make consuming the stream output of an Augmenta server as easy as possible.
As of right now this only refers to the data emitted through websocket by the Websocket Output node, but other network protocols might be added later on.

## Building
We use CMake as our buildsystem.
## Features
The SDK can be used to parse different type of data received from Augmenta:
- **Tracking data** : A list of tracked objects/persons with their ID, position, bounding box and velocity
- **Volumetric data** : Filtered point cloud data, either per-cluster, per-zone, or from the whole scene
- **Zones events** : Be notified of events like enter, leave, presence... affecting a specific zone in the world
- **World hierarchy** : The structure of the world as set up on Augmenta's side: scenes, zones, etc.

Features yet to be implemented are:
- **Skeleton tracking**
- **Custom cluster data**

## Protocol
This SDK can help you parse data received from the server, but you'll still need to respect the [Augmenta Websocket Protocol Specification](https://augmentatech.notion.site/Augmenta-WebSocket-Protocol-Specification-v2-637551d8e04a4015a56526d80e1b10f0?pvs=74). Make sure to give it a read !

## Using the SDK
### Integrate in your project
The SDK is composed of a single header/implementation file pair. We provide support for CMake. You can integrate it the way you see fit:
- using CMake
- as a git submodule
- by dropping the files directly in your project

### Implement in your codebase
The SDK revolves around creating an `Augmenta::Client` object and using it to parse data blobs and messages received.
See [examples/Example.cpp](examples/Example.cpp) for a full usage example.

### Websocket implementation
This SDK does not come with a websocket implementation, as we expect most users' environments to contain one already. If that is not the case we can recommend the [websocketpp](https://github.com/zaphoyd/websocketpp) library.

### Lifetime
Augmenta's servers and software are designed to run perpetually. They will automatically restarts in case of crashes, reboot, power loss, etc.
Make sure to take this into account and handle the connection lifecycle properly. For example, you should try to reconnect to the server automatically in case the connection is lost (which could happen in cases of network outage for example).

### Options
Using the SDK, you can select options to control the format and kind of data that the Augmenta server will send (see the implementation for descriptions).

While implementing a client, keep in mind that some of those options should be controllable by your users (which type of data will be sent) while some other might be locked by you, the developper (things like your software's coordinate system).

> **Note:** Changed options will only be taken into account after re-initializing the client.

## Contribute to the SDK
We use CMake as our buildsystem.
To build a standalone version of the lib:

```
Expand All @@ -16,10 +54,8 @@ cmake -B build -S .
cmake --build build
```

## Using the SDK
The SDK revolves around creating an `Augmenta::Client` object and using it to parse data blobs and messages received.
See [examples/Example.cpp](examples/Example.cpp) for a full usage example.

## Dependencies
## Dependencies and ressources
- [zstd](https://github.com/facebook/zstd)
- [nlohmann::json](https://github.com/nlohmann/json)
- [nlohmann::json](https://github.com/nlohmann/json)

> Please reach out to us if you have any questions - Augmenta Team
99 changes: 75 additions & 24 deletions examples/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,41 @@
#include <array>
#include <iostream>

// Sample data types. Replace with your own types !
using Vector3f = std::array<float, 3>;
using String = std::string;

// Sample data types. Replace with your own !
using PointCloud = std::vector<Vector3f>;
struct Cluster {

struct Cluster
{
Vector3f boundingBoxPosition;
Vector3f boundingBoxSize;
Vector3f centroid;
Vector3f velocity;
float weight;
PointCloud pointCloud;
};

struct ZoneEvent
{
std::array<float, 2> xyPad;
int presence;
float sliderValue;
int enters;
int leaves;
PointCloud pointCloud;
};

struct HierarchyObject
{
String type;
String name;
String address;
Vector3f position;
Vector3f orientation;
std::vector<HierarchyObject> children;
};
using String = std::string;

struct ExampleWebSocketClient
{
Expand Down Expand Up @@ -63,65 +91,88 @@ struct ExampleWebSocketClient
// 4 (cont.) ------
void OnDataBlobReceived(const std::vector<std::byte> &dataBlob)
{
// You might want to keep that somewhere else
std::vector<Cluster> frameClusters;
std::vector<PointCloud> frameScenePointClouds;
std::vector<ZoneEvent> frameZoneEvents;

auto parsedData = augmentaClient.parseDataBlob(dataBlob.data(), dataBlob.size());

// Scene info
const auto &sceneInfo = parsedData.getSceneInfo();

String scenePath;
scenePath.resize(sceneInfo.getAddressLength());
sceneInfo.getAddress(scenePath.data());
String scenePath = sceneInfo.getAddress();

// Objects
// Objects (Clusters and Point Clouds)
for (auto &object : parsedData.getObjects())
{
const auto &objectID = object.getID();
if (object.hasCluster())
{
auto &clusterInfo = object.getCluster();

if (clusterInfo.getState() == Augmenta::ClusterState::Entered)

Cluster& cluster = frameClusters.emplace_back();
cluster.boundingBoxPosition = clusterInfo.getBoundingBoxCenter<Vector3f>();
cluster.boundingBoxSize = clusterInfo.getBoundingBoxSize<Vector3f>();
cluster.centroid = clusterInfo.getCentroid<Vector3f>();
cluster.velocity = clusterInfo.getVelocity<Vector3f>();
cluster.weight = clusterInfo.getWeight();

if (object.hasPointCloud())
{
// This is a new cluster, add it to our list
}
// If the object has both a cluster and point cloud property,
// it is the cluster's contained point cloud
auto& pcInfo = object.getPointCloud();

if (clusterInfo.getState() == Augmenta::ClusterState::WillLeave)
{
// Clean up leaving clusters
cluster.pointCloud.resize(pcInfo.getPointCount());
pcInfo.getPointsData(cluster.pointCloud.data());
}
}

if (object.hasPointCloud())
else if (object.hasPointCloud())
{
auto &pcInfo = object.getPointCloud();

// Do something with the data
// For example you can copy the point data to your own data structure.
PointCloud pc;
PointCloud &pc = frameScenePointClouds.emplace_back();
pc.resize(pcInfo.getPointCount());
pcInfo.getPointsData(pc.data());
}
}

// Zones
for (const auto &zone : parsedData.getZones())
// Zone Events
for (const auto &zoneEventInfo : parsedData.getZoneEvents())
{
for (const auto &property : zone.getProperties())
const auto emitterZoneAddress = zoneEventInfo.getEmitterZoneAddress();
// You could use that to map the event to your zone struct

ZoneEvent& zoneEvent = frameZoneEvents.emplace_back();
zoneEvent.enters = zoneEventInfo.getEnters();
zoneEvent.leaves = zoneEventInfo.getLeaves();
zoneEvent.presence = zoneEventInfo.getPresence();

for (const auto &property : zoneEventInfo.getProperties())
{
switch (property.getType())
{
case Augmenta::DataBlob::ZoneEventPacket::Property::Type::Slider:
{
const auto &sliderData = property.getSliderParameters();
auto value = sliderData->getValue();
zoneEvent.sliderValue = sliderData->getValue();
break;
}
case Augmenta::DataBlob::ZoneEventPacket::Property::Type::XYPad:
{
const auto &xyData = property.getXYPadParameters();
auto x = xyData->getX();
auto y = xyData->getY();
zoneEvent.xyPad = {xyData->getX(), xyData->getY()};
break;
}
case Augmenta::DataBlob::ZoneEventPacket::Property::Type::PointCloud:
{
const auto& pcParams = property.getPointCloudParameters();
zoneEvent.pointCloud.resize(pcParams->getPointCount());
pcParams->getPointsData(zoneEvent.pointCloud.data());
}
// ...
}
}
}
Expand Down
Loading