Skip to content

Commit 0ea72fb

Browse files
authored
Merge pull request #43 from tomsch420/main
Documentation on the ORM
2 parents 1fbd7bc + d77dcb2 commit 0ea72fb

12 files changed

Lines changed: 583 additions & 443 deletions

File tree

.github/workflows/notebook-test-ci.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,12 @@ jobs:
6060
run: |
6161
source /opt/ros/overlay_ws/src/semantic_world-venv/bin/activate
6262
cd /opt/ros/overlay_ws/src/semantic_world/examples
63-
rm -rf tmp
64-
mkdir tmp
6563
python -m jupytext --to notebook *.md
66-
mv *.ipynb tmp && cd tmp
6764
6865
- name: Run tests
6966
run: |
7067
source /opt/ros/overlay_ws/install/setup.bash
7168
source /opt/ros/overlay_ws/src/semantic_world-venv/bin/activate
72-
cd /opt/ros/overlay_ws/src/semantic_world/examples/tmp
73-
python -m treon --thread 1 -v --exclude=migrate_neems.ipynb --exclude=improving_actions.ipynb
69+
cd /opt/ros/overlay_ws/src/semantic_world/examples/
70+
python -m treon --thread 1 -v
71+
rm *.ipynb

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ __pycache__
44
.hypothesis
55
_build
66
*.egg-info
7-
build
7+
build
8+
resources/procthor_environments

doc/_toc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ parts:
1313
- caption: Examples
1414
chapters:
1515
- file: examples/graph_of_convex_sets
16+
- file: examples/orm_querying
1617
- caption: References
1718
chapters:
1819
- file: autoapi/index

doc/intro.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,10 @@ The entire world can be saved to any database
5656
that has an [sqlalchemy](https://docs.sqlalchemy.org/en/20/index.html) connector.
5757
The definitions and relationships for the database are automatically derived from the datastructures
5858
derived in the python package via the [ormatic](https://github.com/tomsch420/ormatic) package.
59-
Since the datastructures for the forward calculations of the world are not defined compatibly, the types
60-
from {py:mod}`semantic_world.spatial_types.spatial_types` are mapped via JSON as columns.
61-
This is due to the fact, that this package uses casadi to speed up forward kinematics.
6259
The types for sqlalchemy are defined in {py:mod}`semantic_world.orm.model`.
6360
The interface to sqlalchemy is auto-generated to {py:mod}`semantic_world.orm.ormatic_interface`.
64-
The script
65-
to recreate the interface is found in [here](https://github.com/cram2/semantic_world/blob/main/scripts/generate_orm.py).
61+
The script to recreate the interface is found in [here](https://github.com/cram2/semantic_world/blob/main/scripts/generate_orm.py).
62+
63+
Learn more about the ORM in [this tutorial](orm-guide).
6664

6765

examples/orm_querying.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
jupytext:
3+
text_representation:
4+
extension: .md
5+
format_name: myst
6+
format_version: 0.13
7+
jupytext_version: 1.17.2
8+
kernelspec:
9+
display_name: Python 3
10+
language: python
11+
name: python3
12+
---
13+
14+
(orm-guide)=
15+
# ORM Guide
16+
17+
The semantic world comes with an ORM attached to it that is derived from the python datastructures.
18+
The ORM can be used to serialize entire worlds into an SQL database and retrieve them later. The semantic annotations (views) are stored alongside the kinematic information.
19+
The queried worlds are full objects that can be reconstructed into the original objects without any problems.
20+
Let's go into an example where we create a world, store it, retrieve and reconstruct it.
21+
First, lets load a world from a URDF file.
22+
23+
```{code-cell} ipython2
24+
import os
25+
26+
import rclpy
27+
from sqlalchemy import create_engine, select
28+
from sqlalchemy.orm import Session
29+
30+
from ormatic.dao import to_dao
31+
from semantic_world.adapters.urdf import URDFParser
32+
from semantic_world.orm.ormatic_interface import *
33+
from semantic_world.views import Table
34+
35+
# setup ros 2
36+
rclpy.init()
37+
38+
# set up an in memory database
39+
engine = create_engine('sqlite:///:memory:')
40+
session = Session(engine)
41+
Base.metadata.create_all(bind=session.bind)
42+
43+
# load the table world from urdf
44+
urdf_dir = os.path.join(os.getcwd(), "..", "resources", "urdf")
45+
table = os.path.join(urdf_dir, "table.urdf")
46+
world = URDFParser(table).parse()
47+
```
48+
49+
Next, we create a semantic annotation that describes the table.
50+
51+
```{code-cell} ipython2
52+
table_view = Table([b for b in world.bodies if "top" in str(b.name)][0])
53+
world.add_view(table_view)
54+
print(table_view)
55+
```
56+
57+
Now, let's store the world to a database. For that, we need to convert it to its data access object which than can be stored in the database.
58+
59+
```{code-cell} ipython2
60+
dao = to_dao(world)
61+
session.add(dao)
62+
session.commit()
63+
```
64+
65+
We can now query the database about the world and reconstruct it to the original instance. As you can see the semantic annotations are also available and fully working.
66+
67+
```{code-cell} ipython2
68+
queried_world = session.scalars(select(WorldMappingDAO)).one()
69+
reconstructed_world = queried_world.from_dao()
70+
table = [view for view in reconstructed_world.views if isinstance(view, Table)][0]
71+
print(table)
72+
print(table.points_on_table(2))
73+
rclpy.shutdown()
74+
```
75+
76+
## Maintaining the ORM 🧰
77+
78+
You can maintain the ORM by maintaining the [generate_orm.py](https://github.com/cram2/semantic_world/blob/main/scripts/generate_orm.py).
79+
In there you have to list all the classes you want to generate mappings for and perhaps some type decorators for advanced use cases.
80+
Whenever you write a new dataclass that should appear or has semantic meaningful content make sure it appears in the set of classes.
81+
Pay attention to the logger during generation and see if it understands your datastructures correctly.
82+
83+
+++
84+
85+
## The sharp bits 🔪
86+
The world class manages the dependencies of the bodies in the world. Whenever you retrieve a body or connection, it comes as a data access object that is disconnected from the world itself.
87+
The relationships to the world exist and can be joined. However, when you reconstruct something else but the world, the reconstructed object does not have a world available. You can always reconstruct the entire world by querying for the objects world instead.

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ casadi~=3.7.0
88
hypothesis
99
pytest
1010
scipy
11-
ormatic>=1.1.8
11+
ormatic>=1.1.10
1212
sqlacodegen
1313
ripple_down_rules>=0.6.51
1414
pytest-order
@@ -19,4 +19,5 @@ random_events
1919
plotly
2020
rtree
2121
daqp
22-
pathlib
22+
pathlib
23+
probabilistic_model

scripts/build_documentation.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
# Get the directory where the script is located
4+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5+
6+
# Navigate to the parent directory of the script (project root)
7+
cd "$SCRIPT_DIR/.." || exit
8+
9+
# Build documentation using jupyter-book
10+
jb build doc
11+
12+
echo "Documentation built successfully!"

0 commit comments

Comments
 (0)