Contents¶
Introduction¶
With the system dynamics and sensors modeled, and all messages defined we can begin setting up the ROS architecture. While for long-term development it is strongly recommended to use the already defined ros_simulator package within ros4crs, this can be a daunting challengs for users new to ROS. In this tutorial we will therefore start by defining our own barebones ROS simulator which calls our dynamical model to advance the state and prints the result to the terminal.
Step-by-Step¶
Setup Folder Structure¶
Let's take a look at crs/src/ros4crs/ros_simulator as a template
ros_simulator
├── app
│ └── simulation_node.cpp
├── CMakeLists.txt
├── config
│ ├── kinematic_car_simulator.yaml
│ └── pacejka_car_simulator.yaml
├── include
│ └── ros_simulator
│ ├── common
│ │ ├── noise_model.h
│ │ └── ros_simulator.h
│ ├── component_registry.h
│ ├── delayed_publisher.h
│ ├── gaussian_noise_model.h
│ ├── ros_kinematic_simulator.h
│ └── ros_pacejka_simulator.h
├── launch
│ ├── default.launch
│ └── default_standalone.launch
├── package.xml
├── src
│ ├── component_registry.cpp
│ ├── ros_kinematic_simulator.cpp
│ └── ros_pacejka_simulator.cpp
└── test
├── config
│ └── test_pacejka_imu_vicon.yaml
├── ros_simulator_test.cpp
└── ros_simulator_test.launch
This obviously contains quite a few files, not all of which are strictly necessary to get a minimal ROS simulator up and running. We can either duplicate the ros_simulator/ directory and trim it down, or create a new one and generate the appropriate files as we go along. In the end we should have a folder-tree which is equivalent to the following:
parafoil_simulator
├── app
│ └── simulation_node.cpp
├── CMakeLists.txt
├── include
├── launch
│ └── parafoil_3dof_launch.launch
├── package.xml
└── src
containing the app, which is what ROS will actually execute, a launch file, which tells ROS what to execute, and the administrative CMakeLists and package files. Note that we have left the include/ folder even though it contains no files, this is because this will be the home of our header files.
Simulator Node¶
(Re)write app/simulation_node.cpp as minimum working example
1. Includes requisite files from model
2. Instantiates `params`, `state`, and `control_input` structs
3. Prints state as sanity check
4. Creates `parafoil_3dof_model` class instance pointer
5. Propagates model forward once
6. returns 0 if successful
#include <ros/ros.h>
#include <casadi/casadi.hpp>
#include <iostream>
#include <parafoil_3dof_model/parafoil_3dof_model_discrete.h>
#include <parafoil_3dof_model/parafoil_3dof_params.h>
#include <parafoil_3dof_model/parafoil_3dof_state.h>
#include <parafoil_3dof_model/parafoil_3dof_input.h>
int main(int argc, char** argv)
{
crs_models::parafoil_3dof_model::parafoil_3dof_params params = {-0.5, -0.25};
crs_models::parafoil_3dof_model::parafoil_3dof_state state = {1.0, 1.0};
crs_models::parafoil_3dof_model::parafoil_3dof_input control_input = {0.0, 0.0};
std::cout << state << std::endl;
std::unique_ptr<crs_models::parafoil_3dof_model::DiscreteFeedforwardModel> model;
model = std::make_unique<crs_models::parafoil_3dof_model::DiscreteFeedforwardModel>(params);
state = model->applyModel(state, control_input, 1.0);
std::cout << state << std::endl;
return 0;
}
Note that unlike in previous tutorials we are not using a 4dof model but rather a 3dof model, this makes no difference besides the dimensions of the parameters, states, inputs. The structure remains the same.
Launch File¶
Write launch file
- sets namespace
- creates node from my package, of the simulation node
<launch>
<group ns = "test_ns">
<node pkg="parafoil_simulator" name="parafoil_simulator" type="simulation_node" output="screen">
</node>
</group>
</launch>
Admin Files¶
Update package.xml
- change pkg
name - change author/maintainer details
- remove unnecessary
dependencies - add your model as
depend
<?xml version="1.0"?>
<package format="2">
<name>parafoil_simulator</name>
<version>0.0.1</version>
<description>TODO </description>
<author email="norrisg@ethz.ch">Griffin Norris</author>
<maintainer email="norrisg@ethz.ch">Griffin Norris</maintainer>
<license>BSD 2-Clause </license>
<buildtool_depend>catkin</buildtool_depend>
<buildtool_depend>catkin_simple</buildtool_depend>
<depend>roscpp</depend>
<depend>dynamic_models</depend>
<!-- Optional Dependencies -->
<depend>parafoil_3dof_model</depend>
<export></export>
</package>
Update CMakeLists.txt
- Change
projectname to match package name - Remove pacejka nd kinematic model library inclusions
- Remove tests
- Change
app/simulation_node.cpp(if file name was changed) - Change library linking to casadi (here explicitly), also remove
stdc++fsweirdness
cmake_minimum_required(VERSION 2.8.3)
project(parafoil_simulator)
set(CMAKE_CXX_STANDARD 17)
find_package(catkin_simple REQUIRED)
find_package(casadi)
catkin_simple()
catkin_package()
#############
# Libraries #
#############
include_directories(
include
${catkin_INCLUDE_DIRS}
)
###############
# Executables #
###############
cs_add_executable(simulation_node
app/simulation_node.cpp
)
target_link_libraries(simulation_node casadi)
##########
# Export #
##########
cs_install()
cs_export(INCLUDE_DIRS ${CATKIN_DEVEL_PREFIX}/include)
Test Simulator¶
- Open a terminal, start crs-docker
-
Build
-
Source
-
Launch
roslaunch <pkg name> <launch file> -
Observe Output
SUMMARY ======== PARAMETERS * /rosdistro: noetic * /rosversion: 1.15.14 NODES /test_ns/ parafoil_simulator (parafoil_simulator/simulation_node) auto-starting new master process[master]: started with pid [4588] ROS_MASTER_URI=http://localhost:11311 setting /run_id to 798e88ee-7878-11ed-9ac4-0242ac120002 process[rosout-1]: started with pid [4598] started core service [/rosout] process[test_ns/parafoil_simulator-2]: started with pid [4601] parafoil_3dof_state: Pos_x: 0.000000 Pos_y: 0.000000 Pos_z: -100.000000 Psi: 0.785398 Psi_rate: 0.000000 [WARNING] No Q Matrix specified for DiscreteParafoil3dofModel. Using identity Matrix! parafoil_3dof_state: Pos_x: 6.993287 Pos_y: 6.993285 Pos_z: -95.280000 Psi: 0.785398 Psi_rate: 0.000000 [test_ns/parafoil_simulator-2] process has finished cleanly log file: /root/.ros/log/798e88ee-7878-11ed-9ac4-0242ac120002/test_ns-parafoil_simulator-2*.log
Up Next¶
Obviously there is not much we can do by simply printing our states to the terminal. In the next tutorial we will make use of those messages we defined by adding a publisher for your states