How to add/remove/query facts from the knowledge base#
This section describes how to add/remove/query the robotโs knowledge base.
Note
You might want to check first ๐ก Knowledge and reasoning to know more about your robotโs knowledge base.
You have two main options to access the knowledge base:
use the Python wrapper, that uses an idiomatic python syntax to add/remove/query facts. If you are programming with Python, we recommend this approach. See section Python API.
use the ROS interface directly: the knowledge base exposes standard topics and services to manipulate knowledge. See section ROS API.
Using the knowledge base from Python#
The Python wrapper makes it easy to update or query the knowledge base from a Python script or mission controller.
Our Python wrapper follows closely the API of the pykb
library: pykb. pykb
examples and
documentation are largely applicable here as well.
If not already running, start the knowledge base:
ros2 launch knowledge_core knowledge_core.launch.py
Then, create a new Python script and import the Python wrapper as follows:
1# first, create a ROS 2
2import rclpy
3from rclpy.node import Node
4
5rclpy.init()
6node = Node("test_kb_client")
7
8# then import the knowledge base API and create a KB instance
9from knowledge_core.api import KB
10kb = KB(node)
You can then add/remove statements with kb += "s p o"
,
kb += ["s1 p1 o1", "s2 p2 o2"]
, kb -="s p o"
, etc.
Then letโs assume that we want to add the following facts to the kb:
โari is-a Robot
โ, โtiago is-a Robot
โ, and โstockbot is-a Robot
โ.
We can do it as it follows:
1kb += ["ari rdf:type Robot",
2 "tiago rdf:type Robot",
3 "stockbot rdf:type Robot"]
We can then query the knowledge base and to retrieve this information:
1for known_robot in kb["?robot rdf:type Robot"]:
2 print(known_robot)
If the facts have been correctly added, you should get ari
, tiago
,
and stockbot
as output.
Letโs now remove some facts from the knowledge base. Suppose we want to
remove the following facts: tiago rdf:type Robot
, and stockbot rdf:type Robot
:
1kb -= "tiago rdf:type Robot"
2kb -= "stockbot rdf:type Robot"
3# or equivalently
4# kb -= ["tiago rdf:type Robot", "stockbot rdf:type Robot"]
5
6for known_robot in kb["?robot rdf:type Robot"]:
7 print(known_robot)
If the facts have been correctly removed, you should only get ari
as output.
Refer to the Python API for more advanced examples, including subscribing to semantic events (i.e., get notifications when e.g. a specific fact becomes true).
Using the knowledge base with the ROS API#
First, start the knowledge base:
ros2 launch knowledge_core knowledge_core.launch.py
You should see the following output on your terminal:
KnowledgeCore
=============
Knowledge base started.
Available topics:
- /kb/add_fact [std_msgs/String]
- /kb/remove_fact [std_msgs/String]
- /kb/active_concepts [kb_msgs/ActiveConcepts]
- /kb/events/<id> [std_msgs/String] for each subscribed event
Available services:
- /kb/manage [kb_msgs/Manage]
- /kb/revise [kb_msgs/Revise]
- /kb/query [kb_msgs/Query]
- /kb/about [kb_msgs/About]
- /kb/label [kb_msgs/About]
- /kb/details [kb_msgs/About]
- /kb/lookup [kb_msgs/Lookup]
- /kb/sparql [kb_msgs/Sparql]
- /kb/events [kb_msgs/Event]
KnowledgeCore exposes two main topics, /kb/add_fact and /kb/remove_fact, to add/remove triples to the knowledge base. Both topics expect a simple string with 3 tokens separated by spaces (if the object is a literal string, use double quotes to escape it).
Note
The topic, /kb/events/<id>
, is used for events: you can subscribe to
specific โsemanticโ events (eg, a given fact becomes true), and get notified.
See the KnowledgeCore API documentation for details.
It also exposes several services, including:
/kb/revise to add/remove facts using a synchronous interface
/kb/query to perform simple queries
/kb/manage to manage the knowledge base (including for instance the wipe-off of all the facts)
For more details about the API please refer to the ROS API.
We are now ready to see how we can add, remove and query the knowledge base.
To add facts to the knowledge base, we can do it using the topics or the
services. For instance, suppose we want to add the following facts: [ari
rdf:type Robot, tiago rdf:type Robot, stockbot rdf:type Robot]
.
1import rclpy
2from rclpy.node import Node
3from std_msgs.msg import String
4from kb_msgs.srv import Revise
5
6rclpy.init()
7node = Node("test_kb_client")
8
9# add a fact by publishing to the /kb/add_fact topic
10facts_pub = node.create_publisher(String, "/kb/add_fact", 1)
11facts_pub.publish(String(data="ari rdf:type Robot"))
12
13# or using the Revise service
14revise = node.create_client(Revise, "/kb/revise")
15revise.wait_for_service(timeout_sec=1.0)
16
17future = revise.call_async(
18 Revise.Request(
19 statements=["tiago rdf:type Robot",
20 "stockbot rdf:type Robot"],
21 method=Revise.Request.ADD
22 ))
23
24# wait for the service to complete
25rclpy.spin_until_future_complete(node, future)
We can then query the knowledge base and check if we can retrieve this information.
26import json
27from kb_msgs.srv import Query
28
29query = node.create_client(Query, "/kb/query")
30query.wait_for_service(timeout_sec=1.0)
31
32future = query.call_async(
33 Query.Request(
34 patterns=["?robot rdf:type Robot"],
35 vars=[],
36 models=[]
37 ))
38
39
40# wait for the service to complete
41rclpy.spin_until_future_complete(node, future)
42
43results = future.result()
44
45print(json.loads(results.json))
If the facts have been correctly added, you should get the following output:
[{'robot': 'stockbot'}, {'robot': 'tiago'}, {'robot': 'ari'}]
Letโs now remove some facts from the knowledge base. Suppose we want to remove
the following facts: [tiago rdf:type Robot, stockbot rdf:type Robot]
.
46# either via topics...
47facts_pub = node.create_publisher(String, "/kb/remove_fact", 1)
48facts_pub.publish(String(data="tiago rdf:type Robot"))
49
50# ...or with a service call
51future = revise.call_async(
52 Revise.Request(
53 statements=["stockbot rdf:type Robot"],
54 method=Revise.Request.DELETE
55 ))
56
57rclpy.spin_until_future_complete(node, future)
We can then query the knowledge base again:
58future = query.call_async(
59 Query.Request(
60 patterns=["?robot rdf:type Robot"],
61 vars=[],
62 models=[]
63 ))
64
65rclpy.spin_until_future_complete(node, future)
66
67results = future.result()
68print(json.loads(results.json))
If the facts have been correctly removed, you should get the following output:
[{'robot': 'ari'}]
Next steps#
Check the KnowledgeCore API for more details about the KnowledgeCore capabilities;
Check the Tutorial: Getting started with the knowledge base for a tutorial involving reasoning.