|
|
# Lab 4: Exploration
|
|
|
|
|
|
The goal of this lab is to fill a knowledge database with information perceived in the environment. You will extend the TST executor of lab3 to listen to a semantic sensor, fill new observation in the database and generate a TST for reaching all the location of interests.
|
|
|
The goal of this lab is to fill a knowledge database with information perceived in the environment. You will extend the TST executor from Lab3 to listen to a semantic sensor, fill new observations in the database and generate a TST for reaching all the locations of interests.
|
|
|
|
|
|
It is *important* to have studied **Lecture 09: Knowledgeable Robots** before starting this lab.
|
|
|
|
|
|
In this lab you will:
|
|
|
* Implement a TST Executor that listen to the semantic sensor topic and fill the database.
|
|
|
* Use the `tst_executor` from lab 3 to explore the environment.
|
|
|
* Implement a TST Executor that listens to the semantic sensor topic and fills the database.
|
|
|
* Use the `tst_executor` from Lab 3 to explore the environment.
|
|
|
* Display the results of the exploration in RViz.
|
|
|
* Generate a TST to drive to all the locations.
|
|
|
|
|
|
## Interfacing with the database
|
|
|
## Interfacing with the Database
|
|
|
|
|
|
For this lab we will use a Postgresql database, with a wrapper called \emph{kDB} which provides ROS services for executing SQL and SPARQL queries.
|
|
|
For this lab, we will only use the SPARQL part.
|
... | ... | @@ -29,7 +29,7 @@ You can reset the content of the database with (you need to stop the database fi |
|
|
rm -rf $HOME/.ros_kdb/stores/
|
|
|
```
|
|
|
|
|
|
### Inserting in the database
|
|
|
### Inserting in the Database
|
|
|
|
|
|
The following service call will insert two objects in the graph named **salientpoints**, one human (with identifier 1) at coordinates `(8,10)` and one table (with identifier 2) at coordinates `(10,12)`:
|
|
|
|
... | ... | @@ -45,9 +45,9 @@ content: '@prefix gis: <http://www.ida.liu.se/~TDDE05/gis> |
|
|
properties:location [ gis:x 10; gis:y 12 ] .'"
|
|
|
```
|
|
|
|
|
|
This will insert two objects, the first has uuid `id1`, coordinate `(8,10)` and is a `human`. The second has uuid `id2`, coordinates `(10,12)` and class `table`.
|
|
|
This will insert two objects, the first has uuid `id1`, coordinate `(8,10)` and is a `human`. The second has uuid `id2`, coordinates `(10,12)` and is of class `table`.
|
|
|
|
|
|
### Querying the database
|
|
|
### Querying the Database
|
|
|
|
|
|
The following query can be used to retrieve all the elements in the database:
|
|
|
|
... | ... | @@ -58,10 +58,10 @@ ros2 service call /kdb_server/sparql_query ros_kdb_interfaces/srv/QueryDatabase |
|
|
query: 'SELECT ?subject ?predicate ?object WHERE { ?subject ?predicate ?object }'"
|
|
|
```
|
|
|
|
|
|
*Note:* this query should be used to check if any triples was added in the database, it should not be used as a solution in the lab.
|
|
|
*Note:* this query should be used to check if any triples were added in the database. It should not be used as a solution for the lab.
|
|
|
|
|
|
|
|
|
The following query can be used to retrieve all the object with their class that are near the point of coordinate `(10, 12)`:
|
|
|
The following query can be used to retrieve all the objects with their classes that are near the point with coordinates `(10, 12)`:
|
|
|
|
|
|
```bash
|
|
|
ros2 service call /kdb_server/sparql_query ros_kdb_interfaces/srv/QueryDatabase "queries:
|
... | ... | @@ -79,21 +79,21 @@ FILTER( 9.9 < ?x && ?x < 10.1 && 11.9 < ?y && ?y < 12.1) . |
|
|
|
|
|
You can use `ros2 service type` to get the type of the `sparql_query` service call and `ros2 interface` to access the definition of the service.
|
|
|
|
|
|
## Semantic sensor
|
|
|
## Semantic Sensor
|
|
|
|
|
|
The sensor output observations on a topic called `/semantic_sensor`. You should use `ros2 topic` and `ros2 interface` to introspect the topic, to find its type, look at the values sent, etc...
|
|
|
The sensor outputs observations on a topic called `/semantic_sensor`. You should use `ros2 topic` and `ros2 interface` to introspect the topic, to find its type, look at the values sent, etc...
|
|
|
|
|
|
# Exploration
|
|
|
|
|
|
In [Lab 3](lab3), you have created a TST executor that move the robot to explore the environment. We will extend the functionality of lab3 and add a new type of TST Executor that can be used to record observations from `/semantic_sensor` and save them in the database.
|
|
|
In [Lab 3](lab3), you have created a TST executor that moves the robot to explore the environment. We will extend the functionality of lab3 and add a new type of TST Executor that can be used to record observations from `/semantic_sensor` and save them in the database.
|
|
|
|
|
|
In `lab3_node`:
|
|
|
|
|
|
* Create a new TST Executor for `record-semantic`, it takes as parameters
|
|
|
* Create a new TST Executor for `record-semantic`, it should take as parameters
|
|
|
- `topic` the name of the topic
|
|
|
- `graphname` the name of the graph used to save the data
|
|
|
* Listen for new observations on the given topic
|
|
|
* Check in the graph specified with `graphname` if the observations are already inserted (using a query). For instance the following query can be used, it should return a single element (you need to replace `someid` and `someclasss` with the correct values from the message):
|
|
|
* Check in the graph specified with `graphname` if the observations are already inserted (using a query). For example, the following query can be used that should return a single element (you need to replace `someid` and `someclasss` with the correct values from the message):
|
|
|
```sparql
|
|
|
PREFIX gis: <http://www.ida.liu.se/~TDDE05/gis>
|
|
|
PREFIX properties: <http://www.ida.liu.se/~TDDE05/properties>
|
... | ... | @@ -102,15 +102,15 @@ SELECT ?x ?y WHERE { <someid> a <someklass> ; |
|
|
properties:location [ gis:x ?x; gis:y ?y ] . }
|
|
|
```
|
|
|
* Take into account the following when calling this query:
|
|
|
- Make sure to keep `<` and `>` they indicate a URI in the query, without them the query is invalid and will not be executed, so you can replace `<someid>` by `<somethingelse>` but not `somethingelse`.
|
|
|
- set the TST parameter for `graphname` in the parameter to the service call.
|
|
|
- This query need to be executed with a service call to `/kdb_server/sparql_query`. You can check the official tutorial for [Python](https://docs.ros.org/en/galactic/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html) or [C++](https://docs.ros.org/en/galactic/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Service-And-Client.html) to learn how to make a service call. You only need the client, not the server, since the server is in the database.
|
|
|
- Make sure to keep `<` and `>` as they indicate a URI in the query. Without them the query is invalid and it will not be executed. So you can replace `<someid>` by `<somethingelse>` but not `somethingelse`.
|
|
|
- Set the TST parameter for `graphname` in the parameter to the service call.
|
|
|
- This query needs to be executed with a service call to `/kdb_server/sparql_query`. You can check the official tutorial for [Python](https://docs.ros.org/en/galactic/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html) or [C++](https://docs.ros.org/en/galactic/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Service-And-Client.html) to learn how to make a service call. You only need the client, not the server, since the server is in the database.
|
|
|
- To wait for the results, you should use `self.executor.spin_until_future_complete(self.future)` (since we use a special `executor`)
|
|
|
- You also need to create `ReentrantCallbackGroup` like you did in the `tst_executor` of Lab3, and add it to the `create_client` function call.
|
|
|
- In the call to `/kdb_server/sparql_query`, the fields `bindings` and `service` are unused for this lab and can be set to an empty string.
|
|
|
* If the object has not been observed yet in the database. Add new observation using the insert triples service call (replace 'salientpoints' with the TST parameter for `graphname`).
|
|
|
* If the object has not been put in the database yet, add new observation using the insert triples service call (replace 'salientpoints' with the TST parameter for `graphname`).
|
|
|
* In C++, add `air_simple_sim_msgs` as a dependency in `CMakeLists.txt`, using `find_package` and setting the correct dependencies for your executable.
|
|
|
* In the following section, we cover hints on how to interpret the results of a queries, including parsing of JSON.
|
|
|
* In the following section, we cover hints on how to interpret the results of queries, including parsing of JSON.
|
|
|
|
|
|
You can test your TST executor with:
|
|
|
|
... | ... | @@ -130,7 +130,7 @@ for row in data["results"]["bindings"]: |
|
|
print(row)
|
|
|
```
|
|
|
|
|
|
**Transformation** If you need to transform points from a frame to an other, you can use `tf2`:
|
|
|
**Transformation** If you need to transform points from one coordinate frame to another, you can use `tf2`:
|
|
|
|
|
|
|
|
|
```python
|
... | ... | @@ -172,7 +172,7 @@ QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(result)); |
|
|
|
|
|
You can check the API online for [QJsonDocument](https://doc.qt.io/qt-5/qjsondocument.html)
|
|
|
|
|
|
**Transformation** If you need to transform points from a frame to an other, you can use `tf2`:
|
|
|
**Transformation** If you need to transform points from one coordinate frame to another, you can use `tf2`:
|
|
|
|
|
|
```c++
|
|
|
|
... | ... | @@ -196,12 +196,12 @@ Where `to_frame_rel` is the destination frame, in our case, it should be `"map"` |
|
|
# Visualisation
|
|
|
|
|
|
In this part you should query the database (using a service call) for all the objects.
|
|
|
And then display the resulting object in rviz.
|
|
|
And then display the resulting objects in RViz.
|
|
|
To do that we can publish `visualization_msgs/MarkerArray` message on a topic. Use `ros2 interface show` to display the structure of the message.
|
|
|
|
|
|
## Python
|
|
|
|
|
|
The following show an example of how to publish a marker to show two cubes in Python, you can add this to a new node (don't forget to update your `setup.py`):
|
|
|
The following shows an example of how to publish a marker to show two cubes in Python. You can add this to a new node (don't forget to update your `setup.py`):
|
|
|
|
|
|
```python
|
|
|
import rclpy
|
... | ... | @@ -268,7 +268,7 @@ In RViz you can select to display a marker array, and you should see two cubes. |
|
|
|
|
|
## C++
|
|
|
|
|
|
The following show an example of how to publish a marker to show two cubes in C++, you can add this to a new node (don't forget to update your `CMakeLists.txt`):
|
|
|
The following shows an example of how to publish a marker to show two cubes in C++, you can add this to a new node (don't forget to update your `CMakeLists.txt`):
|
|
|
|
|
|
```c++
|
|
|
#include <chrono>
|
... | ... | @@ -339,7 +339,7 @@ In RViz you can select to display a marker array, and you should see two cubes. |
|
|
|
|
|
## TST
|
|
|
|
|
|
The final step is to write a simple program that query the database for all the humans (all the objects of class `human`), generate a TST (as a json file) for driving to all the location of the humans (as a sequence of `drive_to`) and execute that TST. For simplicity, you can make your program output the TST to a file and then execute the TST with the service call of lab 3.
|
|
|
The final step is to write a simple program that queries the database for all the humans (all the objects of class `human`), generates a TST (as a json file) for driving to all the locations of the humans (as a sequence of `drive_to`) and execute that TST. For simplicity, you can make your program output the TST to a file and then execute the TST with the service call for lab 3.
|
|
|
|
|
|
# Demonstration
|
|
|
|
... | ... | |