Skip to content

Commit 860e1ce

Browse files
LukasWoodtliTSC21
authored andcommitted
Add unit tests for gimbal controller plugin
1 parent a0b0eb8 commit 860e1ce

8 files changed

+329
-72
lines changed

.travis.yml

+11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ env:
22
global:
33
- CCACHE_DIR=$HOME/.ccache
44
- CMAKE_BUILD="mkdir Build; cd Build; cmake ..; make -j$(nproc) -l$(nproc)"
5+
- CMAKE_UNIT_TEST_BUILD="mkdir Build; cd Build; cmake -DENABLE_UNIT_TESTS=On ..; make -j$(nproc) -l$(nproc); make -j$(nproc) test"
56
- CATKIN_BUILD="mkdir -p ~/catkin_ws/src; cd ~/catkin_ws; catkin init; ln -s ${TRAVIS_BUILD_DIR} src; catkin build -j$(nproc) -l$(nproc) -DBUILD_ROS_INTERFACE=ON"
67
- KINETIC="source /opt/ros/kinetic/setup.bash; ${CATKIN_BUILD}"
78
- MELODIC="source /opt/ros/melodic/setup.bash; ${CATKIN_BUILD}"
@@ -18,6 +19,16 @@ matrix:
1819
env:
1920
- PX4_DOCKER_REPO=px4io/px4-dev-simulation:2019-02-09
2021
- BUILD=${CMAKE_BUILD}
22+
- name: CMake unit tests build and run (Gazebo 9)
23+
os: linux
24+
language: cpp
25+
services:
26+
- docker
27+
cache:
28+
ccache: true
29+
env:
30+
- PX4_DOCKER_REPO=px4io/px4-dev-simulation:2019-02-09
31+
- BUILD=${CMAKE_UNIT_TEST_BUILD}
2132
- name: Catkin build on Ubuntu 16.04 with ROS Kinetic (Gazebo 7)
2233
os: linux
2334
language: cpp

CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,15 @@ if (catkin_FOUND)
387387
SHELLS sh)
388388
endif()
389389

390+
391+
################
392+
## Unit Tests ##
393+
################
394+
include(UnitTests)
395+
396+
add_subdirectory(unit_tests)
397+
398+
390399
#############
391400
## Install ##
392401
#############

README.md

+30
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,36 @@ gazebo worlds/iris.world
120120

121121
Please refer to the documentation of the particular flight stack how to run it against this framework, e.g. [PX4](http://dev.px4.io/simulation-gazebo.html)
122122

123+
124+
## Unit Tests
125+
126+
For building and running test an installation of 'googletest' is needed. On Ubuntu it can be installed with:
127+
128+
```bash
129+
sudo apt-get install libgtest-dev
130+
cd /usr/src/googletest
131+
sudo cmake . && cd googletest
132+
sudo make
133+
sudo cp *.a /usr/lib
134+
```
135+
136+
Building the tests on an other platform than Linux is not yet supported.
137+
138+
For building the tests, the flag `ENABLE_UNIT_TESTS` needs to be provided to cmake.
139+
140+
```bash
141+
mkdir build && cd build
142+
cmake -DENABLE_UNIT_TESTS=On ..
143+
```
144+
145+
Then build and run the tests:
146+
147+
```bash
148+
make && make test
149+
```
150+
151+
When writing test it’s important to be careful which API functions of Gazebo are called. As no Gazebo server is running during the tests some functions can produce undefined behaviour (e.g. segfaults).
152+
123153
## Packaging
124154

125155
### Deb

cmake/UnitTests.cmake

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
option(ENABLE_UNIT_TESTS "Build unit tests for the plugins" OFF)
3+
4+
if(ENABLE_UNIT_TESTS)
5+
6+
enable_testing()
7+
8+
find_package(GTest REQUIRED)
9+
find_package(Threads REQUIRED)
10+
11+
endif(ENABLE_UNIT_TESTS)

include/gazebo_gimbal_controller_plugin.hh

-20
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,6 @@ namespace gazebo
9292
private: void OnYawStringMsg(ConstGzStringPtr &_msg);
9393
#endif
9494

95-
/// \TODO something to move into Angle class
96-
/// \brief returns _angle1 normalized about
97-
/// (_reference - M_PI, _reference + M_PI]
98-
/// \param[in] _angle1 input angle
99-
/// \param[in] _reference reference input angle for normalization
100-
/// \return normalized _angle1 about _reference
101-
private: double NormalizeAbout(double _angle, double _reference);
102-
103-
/// \TODO something to move into Angle class
104-
/// \brief returns shortest angular distance from _from to _to
105-
/// \param[in] _from starting anglular position
106-
/// \param[in] _to end angular position
107-
/// \return distance traveled from starting to end angular positions
108-
private: double ShortestAngularDistance(double _from, double _to);
109-
11095
private: sdf::ElementPtr sdf;
11196

11297
private: std::vector<event::ConnectionPtr> connections;
@@ -150,11 +135,6 @@ namespace gazebo
150135
private: common::PID rollPid;
151136
private: common::PID yawPid;
152137
private: common::Time lastUpdateTime;
153-
154-
private: ignition::math::Vector3d ThreeAxisRot(
155-
double r11, double r12, double r21, double r31, double r32);
156-
private: ignition::math::Vector3d QtoZXY(
157-
const ignition::math::Quaterniond &_q);
158138
};
159139
}
160140
#endif

src/gazebo_gimbal_controller_plugin.cpp

+69-52
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,70 @@ using namespace std;
2424

2525
GZ_REGISTER_MODEL_PLUGIN(GimbalControllerPlugin)
2626

27+
/* Keep these functions in the 'detail' namespace so that they
28+
* can be called from unit tests. */
29+
namespace detail {
30+
/////////////////////////////////////////////////
31+
ignition::math::Vector3d ThreeAxisRot(
32+
double r11, double r12, double r21, double r31, double r32)
33+
{
34+
return ignition::math::Vector3d(
35+
atan2( r31, r32 ),
36+
asin ( r21 ),
37+
atan2( r11, r12 ));
38+
}
39+
40+
/////////////////////////////////////////////////
41+
/// \TODO something to move into Angle class
42+
/// \brief returns _angle1 normalized about
43+
/// (_reference - M_PI, _reference + M_PI]
44+
/// \param[in] _angle1 input angle
45+
/// \param[in] _reference reference input angle for normalization
46+
/// \return normalized _angle1 about _reference
47+
double NormalizeAbout(double _angle, double reference)
48+
{
49+
double diff = _angle - reference;
50+
// normalize diff about (-pi, pi], then add reference
51+
while (diff <= -M_PI)
52+
{
53+
diff += 2.0*M_PI;
54+
}
55+
while (diff > M_PI)
56+
{
57+
diff -= 2.0*M_PI;
58+
}
59+
return diff + reference;
60+
}
61+
62+
/////////////////////////////////////////////////
63+
/// \TODO something to move into Angle class
64+
/// \brief returns shortest angular distance from _from to _to
65+
/// \param[in] _from starting anglular position
66+
/// \param[in] _to end angular position
67+
/// \return distance traveled from starting to end angular positions
68+
double ShortestAngularDistance(double _from, double _to)
69+
{
70+
return NormalizeAbout(_to, _from) - _from;
71+
}
72+
73+
/////////////////////////////////////////////////
74+
ignition::math::Vector3d QtoZXY(
75+
const ignition::math::Quaterniond &_q)
76+
{
77+
// taken from
78+
// http://bediyap.com/programming/convert-quaternion-to-euler-rotations/
79+
// case zxy:
80+
ignition::math::Vector3d result = detail::ThreeAxisRot(
81+
-2*(_q.X()*_q.Y() - _q.W()*_q.Z()),
82+
_q.W()*_q.W() - _q.X()*_q.X() + _q.Y()*_q.Y() - _q.Z()*_q.Z(),
83+
2*(_q.Y()*_q.Z() + _q.W()*_q.X()),
84+
-2*(_q.X()*_q.Z() - _q.W()*_q.Y()),
85+
_q.W()*_q.W() - _q.X()*_q.X() - _q.Y()*_q.Y() + _q.Z()*_q.Z());
86+
return result;
87+
}
88+
}
89+
90+
2791
/////////////////////////////////////////////////
2892
GimbalControllerPlugin::GimbalControllerPlugin()
2993
:status("closed")
@@ -388,32 +452,6 @@ void GimbalControllerPlugin::OnYawStringMsg(ConstGzStringPtr &_msg)
388452
}
389453
#endif
390454

391-
/////////////////////////////////////////////////
392-
ignition::math::Vector3d GimbalControllerPlugin::ThreeAxisRot(
393-
double r11, double r12, double r21, double r31, double r32)
394-
{
395-
return ignition::math::Vector3d(
396-
atan2( r31, r32 ),
397-
asin ( r21 ),
398-
atan2( r11, r12 ));
399-
}
400-
401-
/////////////////////////////////////////////////
402-
ignition::math::Vector3d GimbalControllerPlugin::QtoZXY(
403-
const ignition::math::Quaterniond &_q)
404-
{
405-
// taken from
406-
// http://bediyap.com/programming/convert-quaternion-to-euler-rotations/
407-
// case zxy:
408-
ignition::math::Vector3d result = this->ThreeAxisRot(
409-
-2*(_q.X()*_q.Y() - _q.W()*_q.Z()),
410-
_q.W()*_q.W() - _q.X()*_q.X() + _q.Y()*_q.Y() - _q.Z()*_q.Z(),
411-
2*(_q.Y()*_q.Z() + _q.W()*_q.X()),
412-
-2*(_q.X()*_q.Z() - _q.W()*_q.Y()),
413-
_q.W()*_q.W() - _q.X()*_q.X() - _q.Y()*_q.Y() + _q.Z()*_q.Z());
414-
return result;
415-
}
416-
417455
/////////////////////////////////////////////////
418456
void GimbalControllerPlugin::OnUpdate()
419457
{
@@ -468,10 +506,10 @@ void GimbalControllerPlugin::OnUpdate()
468506

469507
#if GAZEBO_MAJOR_VERSION >= 8
470508
ignition::math::Vector3d currentAnglePRYVariable(
471-
this->QtoZXY(ignition::math::Quaterniond(currentAngleYPRVariable)));
509+
detail::QtoZXY(ignition::math::Quaterniond(currentAngleYPRVariable)));
472510
#else
473511
ignition::math::Vector3d currentAnglePRYVariable(
474-
this->QtoZXY(currentAngleYPRVariable));
512+
detail::QtoZXY(currentAngleYPRVariable));
475513
#endif
476514

477515
/// get joint limits (in sensor frame)
@@ -497,11 +535,11 @@ void GimbalControllerPlugin::OnUpdate()
497535
#endif
498536

499537
// normalize errors
500-
double pitchError = this->ShortestAngularDistance(
538+
double pitchError = detail::ShortestAngularDistance(
501539
pitchLimited, currentAnglePRYVariable.X());
502-
double rollError = this->ShortestAngularDistance(
540+
double rollError = detail::ShortestAngularDistance(
503541
rollLimited, currentAnglePRYVariable.Y());
504-
double yawError = this->ShortestAngularDistance(
542+
double yawError = detail::ShortestAngularDistance(
505543
yawLimited, currentAnglePRYVariable.Z());
506544

507545
// Clamp errors based on current angle and estimated errors from rotations:
@@ -609,24 +647,3 @@ void GimbalControllerPlugin::OnUpdate()
609647
}
610648
}
611649

612-
/////////////////////////////////////////////////
613-
double GimbalControllerPlugin::NormalizeAbout(double _angle, double reference)
614-
{
615-
double diff = _angle - reference;
616-
// normalize diff about (-pi, pi], then add reference
617-
while (diff <= -M_PI)
618-
{
619-
diff += 2.0*M_PI;
620-
}
621-
while (diff > M_PI)
622-
{
623-
diff -= 2.0*M_PI;
624-
}
625-
return diff + reference;
626-
}
627-
628-
/////////////////////////////////////////////////
629-
double GimbalControllerPlugin::ShortestAngularDistance(double _from, double _to)
630-
{
631-
return this->NormalizeAbout(_to, _from) - _from;
632-
}

unit_tests/CMakeLists.txt

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
if(ENABLE_UNIT_TESTS)
3+
4+
add_executable(gazebo_gimbal_controller_plugin_test gazebo_gimbal_controller_plugin_test.cpp)
5+
6+
target_link_libraries(gazebo_gimbal_controller_plugin_test
7+
PRIVATE gazebo_gimbal_controller_plugin
8+
${GTEST_BOTH_LIBRARIES}
9+
${CMAKE_THREAD_LIBS_INIT})
10+
11+
add_test(gazebo_gimbal_controller_plugin_test gazebo_gimbal_controller_plugin_test)
12+
13+
endif(ENABLE_UNIT_TESTS)

0 commit comments

Comments
 (0)