no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
Previous revisionNext revision | |||
— | tutorials:intermediate:json_prolog [2019/04/16 12:37] – fine tuning formatting hawkin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Using JSON Prolog to communicate with KnowRob (v0.7.0) ====== | ||
+ | |||
+ | The following tutorial will show how to query the knowledge base, KnowRob, for information using Prolog queries within LISP and CRAM, using the json-prolog package, and also how to process and extract the data from the gained results. | ||
+ | |||
+ | ==== Prerequisites ==== | ||
+ | |||
+ | We will assume that the previous tutorials have already been completed, and therefore CRAM, roslisp_repl and ROS have been installed. | ||
+ | Make sure you have **Java 8** and **Gradle 5.1** already installed. Otherwise you won't be able to build KnowRob. Other versions could work, but have not been tested yet, so use them at your own risk! | ||
+ | |||
+ | |||
+ | === Installation === | ||
+ | |||
+ | We need to install KnowRob. For that, please follow the tutorial on the [[http:// | ||
+ | //Note:// make sure to select the right branch for your current ROS version. | ||
+ | |||
+ | === Installation troubleshooting === | ||
+ | If it complains about missing **swi-prolog**, | ||
+ | <code bash> | ||
+ | $ sudo apt-get install swi-prolog | ||
+ | </ | ||
+ | |||
+ | Make sure however, that it is **version 7**. There are major problems with locations of libraries with version 8, which is the version suggested by the swi-prolog website. apt-get should install version 7 by default. To make sure, you can check it with: | ||
+ | <code bash> | ||
+ | $ dpkg -s swi-prolog | ||
+ | </ | ||
+ | |||
+ | === Launch === | ||
+ | In addition to a **roscore** and the **roslisp_repl** you need to launch **json_prolog** in a Terminal with the following command: | ||
+ | <code bash> | ||
+ | $ roslaunch json_prolog json_prolog.launch | ||
+ | </ | ||
+ | |||
+ | === CRAM dependencies === | ||
+ | In order for us to be able to communicate with KnowRob from LISP, we need to load the **cram-json-prolog** package in our repl, since it implements the necessary interface for the CRAM to KnowRob communication. We also need **cram-utilities** package in order to process lazy lists. (//Note:// Lazy lists will be explained later in the tutorial. If you are curious and want to jump right there, you can do so by clicking [[json_prolog# | ||
+ | In order to load the packages, do the following in your repl: | ||
+ | |||
+ | Open the Emacs command prompt with **,** and type **ros-load-system**. Hit **enter**. It will ask for you to enter the package you want to load, in which case you type **cram_json_prolog**. Confirm with enter. After a few seconds you should see **compilation finished** at the bottom line of Emacs. Repeat the process for **cram_utilities** as well. | ||
+ | |||
+ | If you want to add these dependencies directly into your package already, you can add them to your .asd file, as '' | ||
+ | |||
+ | If you don't have a robot description currently published (and get thrown an error for that by Emacs), use the following instead: | ||
+ | <code lisp> | ||
+ | CL-USER> (roslisp: | ||
+ | </ | ||
+ | |||
+ | ===== Cram-json-prolog ===== | ||
+ | |||
+ | There are multiple ways to call a query, depending on if one needs only one result or all possible results. We will go through them in the following, explaining the differences between them. In general, it helps if one is familiar with Prolog, since essentially everything that can be done in Prolog, can be done via cram-json-prolog as well. Some Prolog tutorials are provided here: [[http:// | ||
+ | |||
+ | ==== prolog-simple-1 ==== | ||
+ | The simplest way is using the '' | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | </ | ||
+ | |||
+ | The result in this case is: | ||
+ | <code lisp> | ||
+ | CL-USER> (((?X . 1))) | ||
+ | </ | ||
+ | |||
+ | X being the variable we asked Prolog to fill with a value. Whenever Prolog returns a value for a variable, the variable name gets prefixed with a question mark. " | ||
+ | In a [[json_prolog# | ||
+ | |||
+ | ==== prolog-simple ==== | ||
+ | Prolog simple works the same way as '' | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | (((?X . 1)) | ||
+ | . # | ||
+ | : | ||
+ | {1005F52FAB}> | ||
+ | </ | ||
+ | | ||
+ | The result is basically still the same, but it looks a little bit more complex on the first glance. What we get is a list which contains two elements. The first one is a list in a list with two elements which we already know from the previous call with '' | ||
+ | {1005F52FAB}> | ||
+ | |||
+ | ==== lazy lists ==== | ||
+ | The results we obtain from the queries are stored in lazy lists, meaning the information is loaded on demand, resulting in us seeing only one solution of the query. If we want to see all the results, we can expand the list and force LISP to show all of them to us, for example, by using: | ||
+ | |||
+ | <code lisp> | ||
+ | CL-USER> (setq *our-list* (json-prolog: | ||
+ | (((?X . 1)) | ||
+ | . # | ||
+ | : | ||
+ | {1005F52FAB}> | ||
+ | | ||
+ | CL-USER> (cut: | ||
+ | (((?X . 1)) ((?X . 2)) ((?X . 3))) | ||
+ | </ | ||
+ | We save our list in a variable for convenience purposes. This allows us also to expand the so stored list, and we can see all the possible values Prolog found for the variable ''? | ||
+ | |||
+ | If we do the same with '' | ||
+ | <code lisp> | ||
+ | CL-USER> (setq *our-list* (json-prolog: | ||
+ | (((?X . 1))) | ||
+ | CL-USER> (cut: | ||
+ | (((?X . 1))) | ||
+ | </ | ||
+ | |||
+ | In the first case, meaning '' | ||
+ | | ||
+ | ==== Accessing data from Prolog ==== | ||
+ | Now that we have a lazy list with interesting information, | ||
+ | | ||
+ | We can use '' | ||
+ | <code lisp> | ||
+ | CL-USER> (setq *our-list* | ||
+ | | ||
+ | (json-prolog: | ||
+ | </ | ||
+ | |||
+ | This gives us the lazy list. Then we can use '' | ||
+ | <code lisp> | ||
+ | CL-USER> (cut: | ||
+ | 1 | ||
+ | </ | ||
+ | Gives us the result '' | ||
+ | That way, one can extract the necessary information, | ||
+ | |||
+ | You can also see the pattern here probably. Basically, any operation one can perform on a list in LISP, has an equivalent in the '' | ||
+ | |||
+ | It also good practice to add the package the prolog-simple call is used in as a parameter. So instead of the above, use: | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | </ | ||
+ | |||
+ | ==== Importing a package with queries ==== | ||
+ | There are many packages within KnowRob which define different kinds of queries, depending on what kind of data one is working with and what one wants to achieve. Those packages are very useful, and can be imported, so that their queries can be used as well. A package can be imported by doing the following: | ||
+ | |||
+ | <code lisp> | ||
+ | |||
+ | CL-USER> (json-prolog: | ||
+ | (NIL | ||
+ | . # | ||
+ | : | ||
+ | {1006444B3B}> | ||
+ | | ||
+ | </ | ||
+ | | ||
+ | This allows us to use the **knowrob_common** package, which allows us to access many utility functions and also the most commonly used queries of KnowRob. | ||
+ | |||
+ | With this imported package we could now do the following: | ||
+ | |||
+ | <code lisp> | ||
+ | |||
+ | CL-USER (json-prolog: | ||
+ | | ||
+ | . # | ||
+ | :GENERATOR #< | ||
+ | | ||
+ | </ | ||
+ | |||
+ | This query converts the first elements upper case letters into lower case, and stores the obtained result in the '' | ||
+ | |||
+ | An overview of the currently available packages and their queries can be found [[http:// | ||
+ | <code bash> | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | If you call a query for which the package is not loaded yet, Emacs will throw the following error: | ||
+ | | ||
+ | <code lisp> | ||
+ | |||
+ | Prolog query failed: PrologException: | ||
+ | [Condition of type SIMPLE-ERROR] | ||
+ | | ||
+ | </ | ||
+ | | ||
+ | and if you check your terminal, in which the **json_prolog** node is running, there will be a huge java print as well, basically explaining the same thing. | ||
+ | | ||
+ | | ||
+ | ==== Some more information about Prolog in LISP ==== | ||
+ | | ||
+ | If we want to check, if a certain number is member of the list, we must declare the variable accordingly. e.g. | ||
+ | |||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | </ | ||
+ | |||
+ | and while one would expect Prolog to return " | ||
+ | <code lisp> | ||
+ | (NIL) | ||
+ | </ | ||
+ | |||
+ | Meaning a list with only one element, the element being NIL. Since in LISP everything that is not NIL, is '' | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | (NIL) | ||
+ | | ||
+ | CL-USER> (json-prolog: | ||
+ | NIL | ||
+ | </ | ||
+ | |||
+ | We can note that if the result is '' | ||
+ | |||
+ | The question is, why is that so? | ||
+ | |||
+ | |||
+ | The json-prolog returns a list of all possible bindings that can be true for the Prolog query. For example, | ||
+ | <code lisp> | ||
+ | CL-USER> (cut: | ||
+ | </ | ||
+ | returns a list of bindings for X and Y (Note: '' | ||
+ | <code lisp> | ||
+ | (((?X . 1) (?Y . 3)) ((?X . 2) (?Y . 3))) | ||
+ | </ | ||
+ | whereas | ||
+ | <code lisp> | ||
+ | CL-USER> (json-prolog: | ||
+ | </ | ||
+ | |||
+ | doesn' | ||