How to stream ODS data
By default, this example uses the configuration available with the examples.
/*
* Copyright 2021-present ifm electronic, gmbh
* SPDX-License-Identifier: Apache-2.0
*
* This example assumes that an instance of ODS is configured
* and switched to RUN state.
*/
#include <iostream>
#include <stdexcept>
#include <thread>
#include "ods_config.hpp"
#include "ods_get_data.hpp"
#include <ifm3d/deserialize/struct_o3r_ods_info_v1.hpp>
#include <ifm3d/deserialize/struct_o3r_ods_occupancy_grid_v1.hpp>
#include <ifm3d/device/o3r.h>
int main() {
///////////////////////////////////////////////////
// Variables needed for the example
///////////////////////////////////////////////////
std::string config_extrinsic_path = "../configs/extrinsic_one_head.json";
std::string config_app_path = "../configs/ods_one_head_config.json";
// Declare the device object (one object only, corresponding to the VPU)
auto o3r = std::make_shared<ifm3d::O3R>();
////////////////////////////////////////////////
// Reset the configuration so that we configure
// exactly what this example expects.
////////////////////////////////////////////////
std::clog << "Resetting the applications" << std::endl;
o3r->Reset({"/applications"});
try {
std::clog << "Trying to get data from app before instantiating"
<< std::endl;
ODSStream ods_stream(o3r, "app0",
{ifm3d::buffer_id::O3R_ODS_INFO,
ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID},
500, 5);
} catch (...) { // Failing silently to continue with the tutorial.
std::clog << "ODSStream cannot be configured with inexistent app0.\n"
<< "This is expected, continuing with the example." << std::endl;
}
ODSConfig ods_config(o3r);
// TODO: change path to config file
// Assuming a camera facing forward, label up,
// 60 cm above the floor.
// We keep the extrinsic calibration and the ODS configuration
// separate for clarity. You can keep all configurations
// in one file if necessary.
ods_config.SetConfigFromFile(config_extrinsic_path);
ods_config.SetConfigFromFile(config_app_path);
// We did not start the application when configuring it,
// so we need to start it now (change state to "RUN")
ods_config.SetConfigFromStr(
R"({"applications": {"instances": {"app0": {"state": "RUN"}}}})");
////////////////////////////////////////////////
// Instantiate the ODSStream object: we expect an
// app called "app0". If your app is different,
// change the app name below.
////////////////////////////////////////////////
std::string app_name = "app0"; // HERE change to your app name
// Here we are starting data streams for both the
// zones and the occupancy grid. This can be changed
// by removing unwanted data streams from the buffer
// list.
ODSStream ods_stream(o3r, app_name,
{ifm3d::buffer_id::O3R_ODS_INFO,
ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID},
500, 5);
ods_stream.StartODSStream();
std::this_thread::sleep_for(std::chrono::seconds(2));
// Loop and display current zones and occupancy grid information
// for duration d
int d = 5;
for (auto start = std::chrono::steady_clock::now(), now = start;
now < start + std::chrono::seconds{d};
now = std::chrono::steady_clock::now()) {
auto zones = ods_stream.GetZones();
auto grid = ods_stream.GetOccGrid();
if (zones){
std::clog << "Current zone occupancy:\n"
<< std::to_string(zones.value().zone_occupied[0]) << ", "
<< std::to_string(zones.value().zone_occupied[1]) << ", "
<< std::to_string(zones.value().zone_occupied[2]) << std::endl;
}
if (grid){
std::clog << "Current occupancy grid's middle cell:\n"
<< std::to_string(grid.value().image.at<uint8_t>(100, 100)) << std::endl;
}
}
std::cout << "Finished getting data from ODS\n";
ods_stream.StopODSStream();
return 0;
}
/*
* Copyright 2022-present ifm electronic, gmbh
* SPDX-License-Identifier: Apache-2.0
*/
#include <chrono>
#include <ifm3d/deserialize/struct_o3r_ods_info_v1.hpp>
#include <ifm3d/deserialize/struct_o3r_ods_occupancy_grid_v1.hpp>
#include <ifm3d/device/o3r.h>
#include <ifm3d/fg.h>
#include <iostream>
#include <queue>
#include <stdexcept>
#include <thread>
using namespace ifm3d::literals;
class ODSDataQueue {
public:
std::queue<ifm3d::Buffer> zones_queue;
std::queue<ifm3d::Buffer> occ_grid_queue;
int queue_size;
ODSDataQueue(int queue_size_ = 5): queue_size(queue_size_){}
void AddFrame(ifm3d::Frame::Ptr frame) {
if (frame->HasBuffer(ifm3d::buffer_id::O3R_ODS_INFO)) {
if (zones_queue.size() > queue_size) {
zones_queue.pop();
}
zones_queue.push(frame->GetBuffer(ifm3d::buffer_id::O3R_ODS_INFO));
}
if (frame->HasBuffer(ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID)) {
if (occ_grid_queue.size() > queue_size) {
zones_queue.pop();
}
occ_grid_queue.push(
frame->GetBuffer(ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID));
}
}
ifm3d::ODSInfoV1 GetZones() {
// Calling this function on an empty queue will cause undefined behavior.
auto zones = ifm3d::ODSInfoV1::Deserialize(zones_queue.front());
zones_queue.pop();
return zones;
}
ifm3d::ODSOccupancyGridV1 GetOccGrid() {
// Calling this function on an empty queue will cause undefined behavior.
auto grid = ifm3d::ODSOccupancyGridV1::Deserialize(occ_grid_queue.front());
occ_grid_queue.pop();
return grid;
}
};
class ODSStream {
public:
ODSStream(ifm3d::O3R::Ptr o3r_, std::string app_name_,
ifm3d::FrameGrabber::BufferList buffer_ids_, int timeout_, int queue_size_): o3r(o3r_), app_name(app_name_), buffer_ids(buffer_ids_), timeout(timeout_), queue_size(queue_size_), data_queue(queue_size){
std::string j_string =
"/applications/instances/" + app_name + "/data/pcicTCPPort";
ifm3d::json::json_pointer j(j_string);
auto FG_PCIC_PORT = o3r->Get({j_string})[j];
fg = std::make_shared<ifm3d::FrameGrabber>(o3r, FG_PCIC_PORT);
}
void StartODSStream() {
std::clog << "Starting data stream" << std::endl;
fg->Start(buffer_ids);
fg->OnNewFrame([this](auto frame) { this->data_queue.AddFrame(frame); });
}
void StopODSStream() {
std::clog << "Stopping data stream" << std::endl;
fg->Stop();
}
std::optional<ifm3d::ODSInfoV1> GetZones() {
if (!data_queue.zones_queue.empty()) {
auto zones = data_queue.GetZones();
return zones;
}
return {};
}
std::optional<ifm3d::ODSOccupancyGridV1> GetOccGrid() {
if (!data_queue.occ_grid_queue.empty()) {
auto occ_grid = data_queue.GetOccGrid();
return occ_grid;
}
return {};
}
private:
ifm3d::O3R::Ptr o3r;
std::string app_name;
ifm3d::FrameGrabber::Ptr fg;
ifm3d::FrameGrabber::BufferList buffer_ids = {
ifm3d::buffer_id::O3R_ODS_INFO, ifm3d::buffer_id::O3R_ODS_OCCUPANCY_GRID};
int queue_size = 5;
ODSDataQueue data_queue;
int timeout = 500; // Timeout in milliseconds
};