-
Notifications
You must be signed in to change notification settings - Fork 0
Create PoC of SLAM functionality using Gaia #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| logs/ | ||
| .gaia_slam_db | ||
| cmake-* | ||
| .idea | ||
| .clang-tidy | ||
| .clang-format |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| ################################################### | ||
| # Copyright (c) Gaia Platform LLC | ||
| # | ||
| # Use of this source code is governed by the MIT | ||
| # license that can be found in the LICENSE.txt file | ||
| # or at https://opensource.org/licenses/MIT. | ||
| ################################################### | ||
|
|
||
| cmake_minimum_required(VERSION 3.16) | ||
|
|
||
| project(gaia_slam) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 17) | ||
|
|
||
| # We need pthreads support. | ||
| set(CMAKE_THREAD_PREFER_PTHREAD TRUE) | ||
| set(THREADS_PREFER_PTHREAD_FLAG TRUE) | ||
| find_package(Threads REQUIRED) | ||
|
|
||
| include("/opt/gaia/cmake/gaia.cmake") | ||
|
|
||
| # --- Generate Direct Access classes from DDL--- | ||
| process_schema( | ||
| DDL_FILE ${PROJECT_SOURCE_DIR}/gaia/gaia_slam.ddl | ||
| DATABASE_NAME gaia_slam | ||
| ) | ||
|
|
||
| # -- Translate ruleset into CPP -- | ||
| translate_ruleset( | ||
| RULESET_FILE ${PROJECT_SOURCE_DIR}/gaia/gaia_slam.ruleset | ||
| DATABASE_NAME gaia_slam | ||
| CLANG_PARAMS | ||
| -I ${PROJECT_SOURCE_DIR}/include | ||
| ) | ||
|
|
||
| # | ||
| # Direct Access Example | ||
| # | ||
| add_executable(gaia_slam_direct_access | ||
| src/main_direct_access.cpp | ||
| src/graph.cpp | ||
| ) | ||
|
|
||
| target_add_gaia_generated_sources(gaia_slam_direct_access) | ||
|
|
||
| target_include_directories(gaia_slam_direct_access PRIVATE | ||
| ${GAIA_INC} | ||
| ${PROJECT_SOURCE_DIR}/include | ||
| ) | ||
|
|
||
| target_link_libraries(gaia_slam_direct_access PRIVATE | ||
| ${GAIA_LIB} | ||
| Threads::Threads | ||
| ) | ||
|
|
||
| # | ||
| # Rules Example | ||
| # | ||
| add_executable(gaia_slam_rules | ||
| src/main_rules.cpp | ||
| src/graph.cpp | ||
| ) | ||
|
|
||
| target_add_gaia_generated_sources(gaia_slam_rules) | ||
|
|
||
| target_include_directories(gaia_slam_rules PRIVATE | ||
| ${GAIA_INC} | ||
| ${PROJECT_SOURCE_DIR}/include | ||
| ) | ||
|
|
||
| target_link_libraries(gaia_slam_rules PRIVATE | ||
| ${GAIA_LIB} | ||
| Threads::Threads | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| This example aims at teaching Gaia concepts using a real-world use-case scenario (SLAM). This is only for demonstration | ||
| purposes and does not aim to be a real solution for SLAM. | ||
|
|
||
| Still, you can appreciate some elements of Graph-based SLAM such as the graph data structure (`graph`, `vertex`, `edge`), | ||
| observation of the external world (`incoming_data_event`), and building of the graph elements when new observations come in. | ||
|
|
||
| The data model (the SLAM graph) is defined in `gaia/gaia_slam.ddl`, while the rules are defined in `gaia/gaia_slam.ruleset`. | ||
|
|
||
| There are two executables: | ||
| 1. `src/main_rules.cpp`: Shows how mutating the database triggers the rules in `gaia/gaia_slam.ruleset`. | ||
| 2. `src/main_direct_access.cpp`: Show how to manipulate the Graph using the direct_access API. This code does not use rules. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| ---------------------------------------------------- | ||
| -- Copyright (c) Gaia Platform LLC | ||
| -- | ||
| -- Use of this source code is governed by the MIT | ||
| -- license that can be found in the LICENSE.txt file | ||
| -- or at https://opensource.org/licenses/MIT. | ||
| ---------------------------------------------------- | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tables need an explainer - how do these get used?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a little explanation but not too detail since I'm no SLAM expert. |
||
| database gaia_slam | ||
|
|
||
| -- SLAM graph. | ||
| table graph | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to what bill said. plus a good part in the readme.md detailing why, what, etc.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added readme with pretty much same code content as the description of this PR. |
||
| ( | ||
| id string unique, | ||
| vertices references vertex[], | ||
| edges references edge[] | ||
| ) | ||
|
|
||
| -- A new vertex is created every time a new observation from a sensor is done. | ||
| table vertex | ||
| ( | ||
| id uint64 unique, | ||
| type uint8, | ||
| data uint8[], | ||
| pose_x double, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an obvious candidate for a nested struct when we support complex types... |
||
| pose_y double, | ||
|
|
||
| -- Relationships | ||
| graph_id string, | ||
| graph references graph | ||
| using vertices | ||
| where vertex.graph_id = graph.id, | ||
|
|
||
| in_edges references edge[], | ||
| out_edges references edge[] | ||
| ) | ||
|
|
||
| -- A new edge is created between every new created vertex and the previous one. | ||
| table edge | ||
| ( | ||
| id uint64 unique, | ||
|
|
||
| -- Relationships | ||
| graph_id string, | ||
| graph references graph | ||
| where edge.graph_id = graph.id, | ||
|
|
||
| dest_id uint64, | ||
| dest references vertex | ||
| using in_edges | ||
| where edge.dest_id = vertex.id, | ||
|
|
||
| src_id uint64, | ||
| src references vertex | ||
| using out_edges | ||
| where edge.src_id = vertex.id | ||
| ) | ||
|
|
||
| -- This table represents a generic input from a sensor. | ||
| -- i.e. Lidar sensor, image, etc.. | ||
| -- Note: this is just an example. | ||
| table incoming_data_event | ||
| ( | ||
| id uint64 unique, | ||
| type uint8, | ||
| data uint8[], | ||
| pose_x double, | ||
| pose_y double | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| //////////////////////////////////////////////////// | ||
| // Copyright (c) Gaia Platform LLC | ||
| // | ||
| // Use of this source code is governed by the MIT | ||
| // license that can be found in the LICENSE.txt file | ||
| // or at https://opensource.org/licenses/MIT. | ||
| //////////////////////////////////////////////////// | ||
|
|
||
| #include <atomic> | ||
|
|
||
| #include <gaia/logger.hpp> | ||
|
|
||
| constexpr uint64_t c_first_vertex_id = 0; | ||
| std::atomic<uint64_t> c_last_edge_id = 0; | ||
|
|
||
| // The serial_group() keyword makes the rules in the ruleset run serially: | ||
| // only one rule is executed at a time. This prevents transaction | ||
| // conflicts when modifying the same data. | ||
| ruleset data_processing : serial_group() | ||
| { | ||
|
|
||
| // Process an incoming data event by creating a new vertex in the graph. | ||
| on_insert(incoming_data_event) | ||
| { | ||
| gaia_log::app().info("Processing incoming_data_event(id: {})", id); | ||
|
|
||
| // The loop below finds the maximum id value for existing edge ids. | ||
| // In practice, we wouldn't search the table each time to look for | ||
| // a new ID. This is only done to provide an example of searching | ||
| // a table. | ||
| // The leading slash '/' means to search through all records in the | ||
| // specified table. | ||
| uint64_t max_vertex_id = c_first_vertex_id; | ||
| for (/v:vertex) | ||
| { | ||
| if (v.id > max_vertex_id) | ||
| { | ||
| max_vertex_id = v.id; | ||
| } | ||
| } | ||
|
|
||
| uint64_t new_vertex_id = max_vertex_id + 1; | ||
| gaia_log::app().info("Creating new vertex(id: {})", new_vertex_id); | ||
|
|
||
| // Create a vertex record | ||
| std::string graph_id_string("graph_1"); | ||
| vertex.insert( | ||
| id: new_vertex_id, | ||
| type: incoming_data_event.type, | ||
| data: incoming_data_event.data, | ||
| pose_x: incoming_data_event.pose_x, | ||
| pose_y: incoming_data_event.pose_y, | ||
| graph_id: graph_id_string.c_str() | ||
| ); | ||
| } | ||
|
|
||
| // Process each new vertex by creating an edge with the previous existing vertex. | ||
| on_insert(vertex) | ||
| { | ||
| gaia_log::app().info("Processing vertex(id: {})", id); | ||
|
|
||
| if (vertex.id == c_first_vertex_id) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| uint64_t prev_vertex_id = vertex.id - 1; | ||
| uint64_t new_edge_id = c_last_edge_id.fetch_add(1); | ||
| gaia_log::app().info( | ||
| "Creating edge(id: {}) with between vertex(id: {}) and vertex(id: {})", | ||
| new_edge_id, prev_vertex_id, vertex.id); | ||
|
|
||
| edge.insert( | ||
| id: new_edge_id, | ||
| graph_id: vertex.graph_id, | ||
| src_id: prev_vertex_id, | ||
| dest_id: vertex.id); | ||
| } | ||
| } | ||
|
|
||
| ruleset graph_processing | ||
| { | ||
| // Reacts to the creation of an edge by just printing it. | ||
| // This rule could contain part of the SALM algorithm. | ||
| on_insert(edge) | ||
| { | ||
| gaia_log::app().info( | ||
| "Created edge(id: {}) vertex(id: {}) -> vertex(id: {})", | ||
| edge.id, edge.src_id, edge.dest_id); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| //////////////////////////////////////////////////// | ||
| // Copyright (c) Gaia Platform LLC | ||
| // | ||
| // Use of this source code is governed by the MIT | ||
| // license that can be found in the LICENSE.txt file | ||
| // or at https://opensource.org/licenses/MIT. | ||
| //////////////////////////////////////////////////// | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <gaia_gaia_slam.h> | ||
|
|
||
| namespace gaia::gaia_slam::graph | ||
| { | ||
|
|
||
| graph_t create_graph(const std::string& uuid); | ||
|
|
||
| vertex_t create_vertex(const graph_t& graph, int64_t id, int64_t vertex_type); | ||
|
|
||
| edge_t create_edge(int64_t id, const vertex_t& src, const vertex_t& dest); | ||
|
|
||
| void clear_data(); | ||
|
|
||
| } // namespace gaia::gaia_slam::graph |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //////////////////////////////////////////////////// | ||
| // Copyright (c) Gaia Platform LLC | ||
| // | ||
| // Use of this source code is governed by the MIT | ||
| // license that can be found in the LICENSE.txt file | ||
| // or at https://opensource.org/licenses/MIT. | ||
| //////////////////////////////////////////////////// | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cstdint> | ||
|
|
||
| namespace gaia::gaia_slam::vertex_type | ||
| { | ||
|
|
||
| static constexpr uint8_t c_lidar_scan = 0; | ||
| static constexpr uint8_t c_image_keyframe = 1; | ||
| static constexpr uint8_t c_visual_landmark = 2; | ||
|
|
||
| } // namespace gaia::gaia_slam::vertex_type |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| //////////////////////////////////////////////////// | ||
| // Copyright (c) Gaia Platform LLC | ||
| // | ||
| // Use of this source code is governed by the MIT | ||
| // license that can be found in the LICENSE.txt file | ||
| // or at https://opensource.org/licenses/MIT. | ||
| //////////////////////////////////////////////////// | ||
|
|
||
| #include "graph.hpp" | ||
|
|
||
| namespace gaia::gaia_slam::graph | ||
| { | ||
|
|
||
| graph_t create_graph(const std::string& id) | ||
| { | ||
| return graph_t::get(graph_t::insert_row(id.c_str())); | ||
| } | ||
|
|
||
| vertex_t create_vertex(const graph_t& graph, int64_t id, int64_t vertex_type) | ||
| { | ||
| vertex_writer vertex_w; | ||
| vertex_w.id = id; | ||
| vertex_w.type = vertex_type; | ||
| vertex_w.graph_id = graph.id(); | ||
|
|
||
| return vertex_t::get(vertex_w.insert_row()); | ||
| } | ||
|
|
||
| edge_t create_edge(int64_t id, const vertex_t& src, const vertex_t& dest) | ||
| { | ||
| if (src.graph_id() == dest.graph_id()) | ||
| { | ||
| throw std::runtime_error("You cannot create an edge from vertices in different graphs!"); | ||
| } | ||
|
|
||
| edge_writer edge_w; | ||
| edge_w.id = id; | ||
| edge_w.src_id = src.id(); | ||
| edge_w.dest_id = dest.id(); | ||
| edge_w.graph_id = src.graph_id(); | ||
|
|
||
| return edge_t::get(edge_w.insert_row()); | ||
| } | ||
|
|
||
| template <typename T_type> | ||
| void clear_table() | ||
| { | ||
| for (auto obj_it = T_type::list().begin(); | ||
| obj_it != T_type::list().end();) | ||
| { | ||
| auto next_obj_it = obj_it++; | ||
| next_obj_it->delete_row(); | ||
| } | ||
| } | ||
|
|
||
| void clear_data() | ||
| { | ||
| clear_table<edge_t>(); | ||
| clear_table<vertex_t>(); | ||
| clear_table<graph_t>(); | ||
| clear_table<incoming_data_event_t>(); | ||
| } | ||
|
|
||
| } // namespace gaia::gaia_slam::graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why C++17? Do we use C++17 features in this app?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure, but I don't see a reason not to use it. (Well actually i do since our DAC headers use C++17 features, it's a known problem, better to proactively avoid warnings).