... | ... | @@ -202,13 +202,13 @@ ros2 service call /execute_tst air_lab_interfaces/srv/ExecuteTst "tst_file: '`ro |
|
|
Note that we use *\`ros2 pkg prefix air_tst\`* which will be replaced by the full path to the directory where the tsts are installed on the system.
|
|
|
* Don't forget to run `tst_executor` and to start it from your screen file.
|
|
|
|
|
|
## Initialise TstML and a load a TstML file
|
|
|
## Initialize TstML and Load a TstML file
|
|
|
|
|
|
First we need to load the Tst definitions in a `TSTNodeModelsRegistry`. `TSTNodeModelsRegistry` is a class from the TstML library, which we are using to implement this lab.
|
|
|
First we need to load the TST definitions in a `TSTNodeModelsRegistry`. `TSTNodeModelsRegistry` is a class from the TstML library, which we are using to implement this lab.
|
|
|
|
|
|
### Python
|
|
|
|
|
|
You will need to create a `TstML.TSTNodeModelsRegistry` and use `loadDirectory` to load all the configuration file. It is best if this `tst_registry` is kept as a class member of your ROS node.
|
|
|
You will need to create a `TstML.TSTNodeModelsRegistry` and use `loadDirectory` to load all the configuration files. It is best if this `tst_registry` is kept as a class member of your ROS node.
|
|
|
|
|
|
```python
|
|
|
import TstML
|
... | ... | @@ -227,7 +227,7 @@ tst_node = TstML.TSTNode.load(filename, tst_registry) |
|
|
|
|
|
### C++
|
|
|
|
|
|
You will need to create a `TstML::TSTNodeModelsRegistry` and use `loadDirectory` to load all the configuration file. It is best if this `tst_registry` is kept as a class member of your ROS node.
|
|
|
You will need to create a `TstML::TSTNodeModelsRegistry` and use `loadDirectory` to load all the configuration files. It is best if this `tst_registry` is kept as a class member of your ROS node.
|
|
|
|
|
|
```c++
|
|
|
#include <TstML/TSTNodeModelsRegistry.h>
|
... | ... | @@ -255,7 +255,7 @@ find_package(TstML REQUIRED) |
|
|
target_link_libraries(tst_executor TstMLExecutor)
|
|
|
```
|
|
|
|
|
|
## Initialise TstML::Executor and start execution
|
|
|
## Initialize TstML::Executor and Start Execution
|
|
|
|
|
|
### Python
|
|
|
|
... | ... | @@ -357,17 +357,17 @@ Instead of displaying the results, you should set the result in the response of |
|
|
|
|
|
## Implement a subclass of a TstML::AbstractNodeExecutor
|
|
|
|
|
|
The main goal of the lab is to implements executors that are subclass `AbstractNodeExecutor` for the terminal TST nodes. In this section, I will give you the implementation of the `undock` executor. **It is not enough to copy the file, you need to understand what every lines do. Once you do, call the lab assistant and explain what you think every line does.**
|
|
|
The main goal of the lab is to implement executors that are subclass of `AbstractNodeExecutor` for the terminal TST nodes. In this section, We will give you the implementation of the `undock` executor. **It is not enough to copy the file, you need to understand what every line does. Once you do, call the lab assistant and explain what you think every line does.**
|
|
|
|
|
|
### Python
|
|
|
|
|
|
Executor should inherit the `TstML::AbstractNodeExecutor` class, they need to implement a `start`, `pause`, `resume`, `stop` and `abort` function. They can access parameters for the TST node in this way:
|
|
|
Executor should inherit the `TstML::AbstractNodeExecutor` class, and the new class needs to implement a `start`, `pause`, `resume`, `stop` and `abort` functions. The class can access parameters for the TST node in this way:
|
|
|
|
|
|
```python
|
|
|
self.node().getParameter(TstML.TSTNode.ParameterType.Specific, "nameoftheparameter")
|
|
|
```
|
|
|
|
|
|
The following show an example of implementation for `undock`:
|
|
|
The following shows an example implementation for `undock`:
|
|
|
|
|
|
```python
|
|
|
import threading
|
... | ... | @@ -454,7 +454,7 @@ class UndockExecutor(TstML.Executor.AbstractNodeExecutor): |
|
|
return TstML.Executor.ExecutionStatus.Aborted()
|
|
|
```
|
|
|
|
|
|
Do not forget to add the `UndockExecutor` to the executor registry, like it was done for `seq` and `conq`. If you want to import class `NameOfClass` from a Python filed called `name_of_file.py`, you can do the following:
|
|
|
Do not forget to add the `UndockExecutor` to the executor registry, like it was done for `seq` and `conq`. If you want to import class `NameOfClass` from a Python file called `name_of_file.py`, you can do the following:
|
|
|
|
|
|
```python
|
|
|
from .name_of_file import NameOfClass
|
... | ... | @@ -462,10 +462,10 @@ from .name_of_file import NameOfClass |
|
|
|
|
|
### C++
|
|
|
|
|
|
Executor should inherit the `AbstractNodeExecutor` class, they need to implement a `start`, `pause`, `resume`, `stop` and `abort` function. They can access parameters for the TST node in this way:
|
|
|
Executor should inherit the `AbstractNodeExecutor` class, and needs to implement a `start`, `pause`, `resume`, `stop` and `abort` functions. The class can access parameters for the TST node in this way:
|
|
|
|
|
|
|
|
|
The following show an example of implementation for `undock`:
|
|
|
The following show an example implementation for `undock`:
|
|
|
|
|
|
```c++
|
|
|
#include <functional>
|
... | ... | @@ -598,7 +598,7 @@ private: |
|
|
|
|
|
Do not forget to add the `UndockExecutor` to the executor registry, like it was done for `seq` and `conq`.
|
|
|
|
|
|
## Test execution
|
|
|
## Test Execution
|
|
|
|
|
|
You should now start your `tst_executor` ROS node, and we can use a service call to execute our first TST:
|
|
|
|
... | ... | @@ -618,7 +618,7 @@ For `abort`, `stop`, `pause` and `resume`, follow those steps: |
|
|
* In that callback function you can use `abort`, `stop`, `pause` and `resume` on the `tst_executor` object you created when starting execution of the tree.
|
|
|
* In the constructor of your ROS Node, you can use the `create_service` function to create a new service. Use the `create_service` of `execute_tst` as an example.
|
|
|
|
|
|
You should to call your services with ```ros2 service call```, however you will notice that the call is hanging, and the execution is not aborted, stopped, paused or resumed. This is because, by default, ROS is single threaded and can only handle one request. We need to use a ```MultiThreadedExecutor``` with a reentrant group.
|
|
|
You should call your services with ```ros2 service call```, however you will notice that the call is hanging, and the execution is not aborted, stopped, paused or resumed. This is because, by default, ROS is single threaded and can only handle one request. We need to use a ```MultiThreadedExecutor``` with a reentrant group.
|
|
|
|
|
|
### Python
|
|
|
|
... | ... | @@ -645,7 +645,7 @@ service = self.create_service(..., callback_group=self.group) |
|
|
|
|
|
Note that the ```execute_tst``` call is not reentrant, and should not be added to the group.
|
|
|
|
|
|
Also, due to a bug in `rclpy` for the version of ROS installed in the labs computers, python exceptions are not displayed when using a `MultiThreadedExecutor`. To work around that problem, it is possible to use the `display_exception` decorator, at the top of your file for the ROS node, add the following:
|
|
|
Also, due to a bug in `rclpy` for the version of ROS installed in the lab computers, python exceptions are not displayed when using a `MultiThreadedExecutor`. To work around that problem, it is possible to use the `display_exception` decorator, at the top of your file for the ROS node, add the following:
|
|
|
|
|
|
```python
|
|
|
import traceback
|
... | ... | @@ -668,7 +668,7 @@ Then just before the function used to define your service callback, add `@displa |
|
|
def execute_tst_callback(self, request, response):
|
|
|
```
|
|
|
|
|
|
You can also check the `UndockExecutor` for an example of use of `@display_exceptions`.
|
|
|
You can also check the `UndockExecutor` for an example use of `@display_exceptions`.
|
|
|
|
|
|
### C++
|
|
|
|
... | ... | @@ -705,8 +705,8 @@ tdde05-cd air_tst tsts |
|
|
|
|
|
* `undock.json`: undock
|
|
|
* `dock.json`: dock
|
|
|
* `drive_to.json`: go to three positions in sequence
|
|
|
* `drive_to_repeat.json`: go to three positions in sequence and repeat once
|
|
|
* `drive_to.json`: go to three positions in a sequence
|
|
|
* `drive_to_repeat.json`: go to three positions in a sequence and repeat once
|
|
|
* `drive_home.json`: go to near the home position and dock
|
|
|
* `explore.json`: execute random exploration motion
|
|
|
* `drive_to_explore.json`: go to a start position and execute the random exploration
|
... | ... | @@ -717,9 +717,9 @@ You need to implement the `dock`, `drive_to` and `explore`. |
|
|
|
|
|
**Dock** Inspire yourself from the `UndockExecutor` to create this executor. Essentially duplicating `UndockExecutor` and replacing Undock by Dock is *almost* all you have to do. You can get the type of an action with `ros2 action info -t [action]`.
|
|
|
|
|
|
**Drive to** Drive to a given location and set the maximum velocity. To drive to a given location, you should send a goal to the navigate action server, like you did in *Lab 2*. Also in this lab you will need to se the `maximum_speed` by publishing on the `/speed_limit` topic. You can use `ros2 topic info` to get the information about a topic, including its type. You can use `ros2 interface show` to show the definition of a topic. `drive_to` has three parameters that you need to get: the destination `p`, the `heading` and the `maximum-speed`.
|
|
|
**Drive to** Drive to a given location and set the maximum velocity. To drive to a given location, you should send a goal to the navigate action server, like you did in *Lab 2*. Also in this lab you will need to set the `maximum_speed` by publishing it on the `/speed_limit` topic. You can use `ros2 topic info` to get the information about a topic, including its type. You can use `ros2 interface show` to show the definition of a topic. `drive_to` has three parameters that you need to get: the destination `p`, the `heading` and the `maximum-speed`.
|
|
|
|
|
|
To get parameters for a TST node, in python:
|
|
|
To get parameters for a TST node, in Python use:
|
|
|
|
|
|
```python
|
|
|
self.node().getParameter(TstML.TSTNode.ParameterType.Specific, "nameoftheparameter")
|
... | ... | @@ -746,7 +746,7 @@ and in C++: |
|
|
node()->hasParameter(TstML::TSTNode::ParameterType::Specific, "nameoftheparameter");
|
|
|
```
|
|
|
|
|
|
Heading is equivalent to Yaw. But it needs to be specify as a quaternion, you can use the following formulat to compute a yaw quaternion:
|
|
|
Heading is equivalent to Yaw. But it needs to be specified as a quaternion. You can use the following formula to compute a yaw in quaternion:
|
|
|
|
|
|
```math
|
|
|
(x=0, y=0,z=sin(yaw/2),q=cos(yaw/2))
|
... | ... | |