jacobian_test.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Copyright (c) 2017 Robert Bosch GmbH.
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * *********************************************************************/
17 
18 #include <gtest/gtest.h>
19 
20 #include <Eigen/Dense>
21 
25 
26 #define EPS_JACOBI 1e-4 // [-]
27 #define EPS_PERTURB 1e-7 // [-]
28 #define SAMPLES 1e6 // [-]
29 #define OPERATING_REGION_X 20.0 // [m]
30 #define OPERATING_REGION_Y 20.0 // [m]
31 #define OPERATING_REGION_THETA 2 * M_PI // [rad]
32 #define OPERATING_REGION_KAPPA 2.0 // [1/m]
33 #define OPERATING_REGION_DELTA_S 0.4 // [m]
34 #define OPERATING_REGION_SIGMA 2.0 // [1/m^2]
35 #define random(lower, upper) (rand() * (upper - lower) / RAND_MAX + lower)
36 #define random_boolean() rand() % 2
37 
38 using namespace std;
39 using namespace steering;
40 
41 typedef Eigen::Matrix<double, 2, 2> Matrix2d;
42 typedef Eigen::Matrix<double, 3, 3> Matrix3d;
43 typedef Eigen::Matrix<double, 3, 2> Matrix32d;
44 
46 {
47  State state;
48  state.x = random(-OPERATING_REGION_X / 2.0, OPERATING_REGION_X / 2.0);
49  state.y = random(-OPERATING_REGION_Y / 2.0, OPERATING_REGION_Y / 2.0);
52  state.d = 0.0;
53  return state;
54 }
55 
57 {
58  Control control;
61  return control;
62 }
63 
64 State integrate_ODE(const State &state, const Control &control, double integration_step)
65 {
66  State state_next;
67  double sigma(control.sigma);
68  double d(sgn(control.delta_s));
69  if (fabs(sigma) > get_epsilon())
70  {
71  end_of_clothoid(state.x, state.y, state.theta, state.kappa, sigma, d, integration_step, &state_next.x,
72  &state_next.y, &state_next.theta, &state_next.kappa);
73  }
74  else
75  {
76  if (fabs(state.kappa) > get_epsilon())
77  {
78  end_of_circular_arc(state.x, state.y, state.theta, state.kappa, d, integration_step, &state_next.x, &state_next.y,
79  &state_next.theta);
80  }
81  else
82  {
83  end_of_straight_line(state.x, state.y, state.theta, d, integration_step, &state_next.x, &state_next.y);
84  }
85  }
86  state_next.theta =
87  pify(state.theta + state.kappa * d * integration_step + 0.5 * sigma * d * integration_step * integration_step);
88  state_next.kappa = state.kappa + sigma * integration_step;
89  state_next.d = d;
90 
91  return state_next;
92 }
93 
94 Matrix3d get_num_motion_jacobi_x(const State &state, const Control &control, double integration_step)
95 {
96  Matrix3d F_x;
97  Matrix3d perturb(EPS_PERTURB * Matrix3d::Identity());
98 
99  State f_x = integrate_ODE(state, control, integration_step);
100  for (int i = 0; i < F_x.cols(); ++i)
101  {
102  // perturb x, y, theta
103  State state_perturb;
104  state_perturb.x = state.x + perturb(0, i);
105  state_perturb.y = state.y + perturb(1, i);
106  state_perturb.theta = state.theta + perturb(2, i);
107  state_perturb.kappa = state.kappa;
108 
109  State f_x_perturb = integrate_ODE(state_perturb, control, integration_step);
110  F_x(0, i) = (f_x_perturb.x - f_x.x) / perturb(i, i);
111  F_x(1, i) = (f_x_perturb.y - f_x.y) / perturb(i, i);
112  F_x(2, i) = (f_x_perturb.theta - f_x.theta) / perturb(i, i);
113  }
114  return F_x;
115 }
116 
117 Matrix32d get_num_motion_jacobi_u(const State &state, const Control &control, double integration_step)
118 {
119  Matrix32d F_u;
120  Matrix2d perturb(EPS_PERTURB * Matrix2d::Identity());
121 
122  State f_u = integrate_ODE(state, control, integration_step);
123  for (int i = 0; i < F_u.cols(); ++i)
124  {
125  // perturb delta_s and kappa
126  Control control_perturb;
127  control_perturb.delta_s = control.delta_s + perturb(0, i);
128  control_perturb.sigma = control.sigma;
129  double integration_step_perturb = fabs(control_perturb.delta_s);
130 
131  State state_perturb;
132  state_perturb.x = state.x;
133  state_perturb.y = state.y;
134  state_perturb.theta = state.theta;
135  state_perturb.kappa = state.kappa + perturb(1, i);
136 
137  State f_u_perturb = integrate_ODE(state_perturb, control_perturb, integration_step_perturb);
138  F_u(0, i) = (f_u_perturb.x - f_u.x) / perturb(i, i);
139  F_u(1, i) = (f_u_perturb.y - f_u.y) / perturb(i, i);
140  F_u(2, i) = (f_u_perturb.theta - f_u.theta) / perturb(i, i);
141  }
142  return F_u;
143 }
144 
145 TEST(Jacobian, F_x)
146 {
147  EKF ekf;
148  for (int i = 0; i < SAMPLES; i++)
149  {
150  State state = get_random_state();
151  Control control = get_random_control();
152 
153  state.kappa = random_boolean() * state.kappa;
154  control.sigma = random_boolean() * control.sigma;
155  double integration_step = fabs(control.delta_s);
156 
157  Matrix3d F_x_ana(Matrix3d::Zero());
158  Matrix32d F_u_ana(Matrix32d::Zero());
159  ekf.get_motion_jacobi(state, control, integration_step, F_x_ana, F_u_ana);
160  Matrix3d F_x_num = get_num_motion_jacobi_x(state, control, integration_step);
161  for (int i = 0; i < F_x_ana.rows(); ++i)
162  {
163  for (int j = 0; j < F_x_ana.cols(); ++j)
164  {
165  EXPECT_LE(fabs(F_x_ana(i, j) - F_x_num(i, j)), EPS_JACOBI);
166  }
167  }
168  }
169 }
170 
171 TEST(Jacobian, F_u)
172 {
173  EKF ekf;
174  for (int i = 0; i < SAMPLES; i++)
175  {
176  State state = get_random_state();
177  Control control = get_random_control();
178 
179  state.kappa = random_boolean() * state.kappa;
180  control.sigma = random_boolean() * control.sigma;
181  double integration_step = fabs(control.delta_s);
182 
183  Matrix3d F_x_ana(Matrix3d::Zero());
184  Matrix32d F_u_ana(Matrix32d::Zero());
185  ekf.get_motion_jacobi(state, control, integration_step, F_x_ana, F_u_ana);
186  Matrix32d F_u_num = get_num_motion_jacobi_u(state, control, integration_step);
187  for (int i = 0; i < F_u_ana.rows(); ++i)
188  {
189  for (int j = 0; j < F_u_ana.cols(); ++j)
190  {
191  EXPECT_LE(fabs(F_u_ana(i, j) - F_u_num(i, j)), EPS_JACOBI);
192  }
193  }
194  }
195 }
196 
197 int main(int argc, char **argv)
198 {
199  testing::InitGoogleTest(&argc, argv);
200  return RUN_ALL_TESTS();
201 }
steering::EKF::get_motion_jacobi
void get_motion_jacobi(const State &state, const Control &control, double integration_step, Matrix3d &F_x, Matrix32d &F_u) const
Computes the Jacobians of the motion equations with respect to the state and control.
Definition: ekf.cpp:78
main
int main(int argc, char **argv)
Definition: jacobian_test.cpp:197
EPS_PERTURB
#define EPS_PERTURB
Definition: jacobian_test.cpp:27
steering::State
Description of a kinematic car's state.
Definition: steering_functions.hpp:44
SAMPLES
#define SAMPLES
Definition: jacobian_test.cpp:28
OPERATING_REGION_DELTA_S
#define OPERATING_REGION_DELTA_S
Definition: jacobian_test.cpp:33
steering::Matrix32d
Eigen::Matrix< double, 3, 2 > Matrix32d
Definition: ekf.hpp:45
get_random_control
Control get_random_control()
Definition: jacobian_test.cpp:56
random
#define random(lower, upper)
Definition: jacobian_test.cpp:35
steering::Control::sigma
double sigma
Sharpness (derivative of curvature with respect to arc length) of a segment.
Definition: steering_functions.hpp:91
integrate_ODE
State integrate_ODE(const State &state, const Control &control, double integration_step)
Definition: jacobian_test.cpp:64
steering::State::theta
double theta
Orientation of the robot.
Definition: steering_functions.hpp:70
steering::pify
double pify(double alpha)
Conversion of arbitrary angle given in [rad] to [-pi, pi[.
Definition: utilities.cpp:83
Matrix3d
Eigen::Matrix< double, 3, 3 > Matrix3d
Definition: jacobian_test.cpp:42
random_boolean
#define random_boolean()
Definition: jacobian_test.cpp:36
steering::State::kappa
double kappa
Curvature at position (x,y)
Definition: steering_functions.hpp:73
Matrix32d
Eigen::Matrix< double, 3, 2 > Matrix32d
Definition: jacobian_test.cpp:43
steering::end_of_straight_line
void end_of_straight_line(double x_i, double y_i, double theta, double direction, double length, double *x_f, double *y_f)
Computation of the end point on a straight line x_i, y_i: initial configuration theta: angle of strai...
Definition: utilities.cpp:216
ekf.hpp
OPERATING_REGION_SIGMA
#define OPERATING_REGION_SIGMA
Definition: jacobian_test.cpp:34
steering::Matrix3d
Eigen::Matrix< double, 3, 3 > Matrix3d
Definition: ekf.hpp:44
steering::State::y
double y
Position in y of the robot.
Definition: steering_functions.hpp:67
TEST
TEST(Jacobian, F_x)
Definition: jacobian_test.cpp:145
steering::Control
Description of a path segment with its corresponding control inputs.
Definition: steering_functions.hpp:82
OPERATING_REGION_Y
#define OPERATING_REGION_Y
Definition: jacobian_test.cpp:30
EPS_JACOBI
#define EPS_JACOBI
Definition: jacobian_test.cpp:26
OPERATING_REGION_KAPPA
#define OPERATING_REGION_KAPPA
Definition: jacobian_test.cpp:32
OPERATING_REGION_X
#define OPERATING_REGION_X
Definition: jacobian_test.cpp:29
steering::end_of_circular_arc
void end_of_circular_arc(double x_i, double y_i, double theta_i, double kappa, double direction, double length, double *x_f, double *y_f, double *theta_f)
Computation of the end point on a circular arc x_i, y_i, theta_i: initial configuration kappa: curvat...
Definition: utilities.cpp:208
OPERATING_REGION_THETA
#define OPERATING_REGION_THETA
Definition: jacobian_test.cpp:31
steering::State::x
double x
Position in x of the robot.
Definition: steering_functions.hpp:64
steering::EKF
Definition: ekf.hpp:48
steering::Control::delta_s
double delta_s
Signed arc length of a segment.
Definition: steering_functions.hpp:85
get_num_motion_jacobi_u
Matrix32d get_num_motion_jacobi_u(const State &state, const Control &control, double integration_step)
Definition: jacobian_test.cpp:117
steering::end_of_clothoid
void end_of_clothoid(double x_i, double y_i, double theta_i, double kappa_i, double sigma, double direction, double length, double *x_f, double *y_f, double *theta_f, double *kappa_f)
Computation of the end point on a clothoid x_i, y_i, theta_i, kappa_i: initial configuration sigma: s...
Definition: utilities.cpp:176
steering::get_epsilon
double get_epsilon()
Return value of epsilon.
Definition: utilities.cpp:57
plot_states.d
d
Definition: plot_states.py:107
std
steering_functions.hpp
steering
Definition: dubins_state_space.hpp:70
get_num_motion_jacobi_x
Matrix3d get_num_motion_jacobi_x(const State &state, const Control &control, double integration_step)
Definition: jacobian_test.cpp:94
steering::sgn
double sgn(double x)
Return sign of a number.
Definition: utilities.cpp:62
steering::Matrix2d
Eigen::Matrix< double, 2, 2 > Matrix2d
Definition: ekf.hpp:43
steering::State::d
double d
Definition: steering_functions.hpp:76
get_random_state
State get_random_state()
Definition: jacobian_test.cpp:45
utilities.hpp
Matrix2d
Eigen::Matrix< double, 2, 2 > Matrix2d
Definition: jacobian_test.cpp:41


steering_functions
Author(s): Holger Banzhaf
autogenerated on Mon Dec 11 2023 03:27:43