fix and re-enable EKF pytests

This commit is contained in:
Daniel Agar
2018-05-03 22:25:36 -04:00
parent 4dabf7a1a8
commit 3a61035ac2
21 changed files with 413 additions and 182 deletions
+20
View File
@@ -80,6 +80,26 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
include_directories(${CMAKE_BINARY_DIR}/matrix-prefix/src/matrix)
add_subdirectory(mathlib)
include(CTest)
enable_testing()
if(BUILD_TESTING)
add_custom_target(check
COMMAND env CTEST_OUTPUT_ON_FAILURE=1 ${CMAKE_CTEST_COMMAND}
DEPENDS ecl_EKF
USES_TERMINAL
)
option(EKF_PYTHON_TESTS "Build the EKF python tests" OFF)
if (EKF_PYTHON_TESTS)
# swig requires -fPIC
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
endif()
add_subdirectory(airdata)
+8 -55
View File
@@ -50,61 +50,14 @@ add_library(ecl_EKF
add_dependencies(ecl_EKF prebuild_targets)
target_include_directories(ecl_EKF PUBLIC ${ECL_SOURCE_DIR})
target_link_libraries(ecl_EKF PRIVATE ecl_geo_lookup)
target_link_libraries(ecl_EKF PRIVATE ecl_geo ecl_geo_lookup mathlib)
# Python bindings & tests
# Use cmake -DPythonTests=1 ../EKF && make pytest
if(PythonTests)
# Use Python 3.5
set(Python_ADDITIONAL_VERSIONS 3.5)
find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp 3 REQUIRED)
set_target_properties(ecl_EKF PROPERTIES PUBLIC_HEADER "ekf.h")
# Need SWIG to wrap ecl
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
add_definitions(-DSWIG_TYPE_TABLE=ecl)
set_source_files_properties(../swig/ecl.i PROPERTIES CPLUSPLUS ON)
set(swigged_sources ekf.h)
# Find numpy include
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy; print(numpy.get_include())" OUTPUT_VARIABLE NUMPY_INCLUDE_DIRS ERROR_QUIET)
include_directories(
..
${MATRIX_DIR}
${EIGEN3_INCLUDE_DIR}
${PYTHON_INCLUDE_DIRS}
${NUMPY_INCLUDE_DIRS}
)
set(SWIG_MODULE_ecl_EXTRA_DEPS ${swigged_sources})
swig_add_module(ecl python ../swig/ecl.i)
swig_link_libraries(ecl ${PYTHON_LIBRARIES} ecl)
add_custom_target(pytest
env PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/ekf_test --verbose
)
add_dependencies(pytest ${SWIG_MODULE_ecl_REAL_NAME})
add_custom_target(pytest-quick
env PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/ekf_test --quick --verbose
)
add_dependencies(pytest-quick ${SWIG_MODULE_ecl_REAL_NAME})
add_custom_target(pytest-benchmark
env PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/ekf_test --benchmark
)
add_dependencies(pytest-benchmark ${SWIG_MODULE_ecl_REAL_NAME})
add_custom_target(pytest-plots
env PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/ekf_test --plots
)
add_dependencies(pytest-plots ${SWIG_MODULE_ecl_REAL_NAME})
add_custom_target(pytest-lint
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/ && ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest/lint
)
add_dependencies(pytest-lint ${SWIG_MODULE_ecl_REAL_NAME})
if(EKF_PYTHON_TESTS)
add_subdirectory(swig)
endif()
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
+42
View File
@@ -0,0 +1,42 @@
############################################################################
#
# Copyright (c) 2015-2018 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name ECL nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
message(STATUS "adding EKF python tests")
include_directories(${ECL_SOURCE_DIR})
# Need SWIG to wrap ecl
find_package(SWIG REQUIRED)
include(${SWIG_USE_FILE})
add_subdirectory(python)
+13 -13
View File
@@ -1,5 +1,5 @@
// SWIG Wrapper for the ecl's EKF
%module(directors="1") ecl
%module(directors="1") ecl_EKF
%feature("autodoc", "3");
%include "inttypes.i"
@@ -11,8 +11,8 @@
%{
#define SWIG_FILE_WITH_INIT
#include <iostream>
#include "../EKF/ekf.h"
#include "../EKF/geo.h"
#include <EKF/ekf.h>
#include <geo/geo.h>
%}
%include "numpy.i"
@@ -142,16 +142,16 @@
}
// Tell swig to wrap ecl classes
%include "../matrix/matrix/Vector3.hpp"
%include "../matrix/matrix/Vector2.hpp"
%include "../matrix/matrix/Quaternion.hpp"
%include "../matrix/matrix/Dcm.hpp"
%include "../matrix/matrix/Euler.hpp"
%include "../matrix/matrix/SquareMatrix.hpp"
%include "../matrix/matrix/helper_functions.hpp"
%include "../EKF/common.h"
%include "../EKF/estimator_interface.h"
%include "../EKF/ekf.h"
%include <matrix/Vector3.hpp>
%include <matrix/Vector2.hpp>
%include <matrix/Quaternion.hpp>
%include <matrix/Dcm.hpp>
%include <matrix/Euler.hpp>
%include <matrix/SquareMatrix.hpp>
%include <matrix/helper_functions.hpp>
%include <EKF/common.h>
%include <EKF/estimator_interface.h>
%include <EKF/ekf.h>
%extend Ekf {
void set_imu_data(uint64_t time_usec, uint64_t delta_ang_dt, uint64_t delta_vel_dt, float delta_ang[3], float delta_vel[3]) {
+40
View File
@@ -0,0 +1,40 @@
# Use Python 3.5
set(Python_ADDITIONAL_VERSIONS 3.5)
find_package(PythonLibs 3 REQUIRED)
find_package(PythonInterp 3 REQUIRED)
include_directories(${PYTHON_INCLUDE_PATH})
# Find numpy include
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy; print(numpy.get_include())" OUTPUT_VARIABLE NUMPY_INCLUDE_DIRS ERROR_QUIET)
include_directories(${NUMPY_INCLUDE_DIRS})
set(CMAKE_SWIG_FLAGS "")
set_source_files_properties(../ecl_EKF.i PROPERTIES CPLUSPLUS ON)
include_directories(../..)
# Add swig module
swig_add_module(ecl_EKF python ../ecl_EKF.i)
swig_link_libraries(ecl_EKF ecl_EKF ${PYTHON_LIBRARIES})
# Files to install with Python
set(PYTHON_INSTALL_FILES
${CMAKE_CURRENT_BINARY_DIR}/ecl_EKF.py
${CMAKE_CURRENT_BINARY_DIR}/_ecl_EKF.so
)
# Configure setup.py and copy to output directory
set(SETUP_PY_IN ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in)
set(SETUP_PY_OUT ${CMAKE_CURRENT_BINARY_DIR}/setup.py)
configure_file(${SETUP_PY_IN} ${SETUP_PY_OUT})
# Declare install target for python
#install(TARGETS swig_example
# COMMAND "${PYTHON_EXECUTABLE} setup.py"
# COMPONENT swig-python)
# Install target to call setup.py
add_custom_target(install-python
DEPENDS _ecl_EKF
COMMAND python ${SETUP_PY_OUT} install
)
+35
View File
@@ -0,0 +1,35 @@
import setuptools.command.install
import shutil
from distutils.sysconfig import get_python_lib
class CompiledLibInstall(setuptools.command.install.install):
"""
Specialized install to install to python libs
"""
def run(self):
"""
Run method called by setup
:return:
"""
# Get filenames from CMake variable
filenames = '${PYTHON_INSTALL_FILES}'.split(';')
# Directory to install to
install_dir = get_python_lib()
# Install files
[shutil.copy(filename, install_dir) for filename in filenames]
if __name__ == '__main__':
setuptools.setup(
name='ecl_EKF',
version='1.0.0-dev',
packages=['ecl_EKF'],
license='BSD 3.0',
author='PX4',
author_email='px4@px4.io',
cmdclass={'install': CompiledLibInstall}
)
+3
View File
@@ -0,0 +1,3 @@
import swig_example
swig_example.swig_example_hello()
swig_example.link_liba_hello()
+43
View File
@@ -0,0 +1,43 @@
############################################################################
#
# Copyright (c) 2015-2018 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name ECL nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
if(BUILD_TESTING)
add_subdirectory(base)
if(EKF_PYTHON_TESTS)
add_subdirectory(pytest)
endif()
add_subdirectory(ringbuffer)
endif()
+7 -11
View File
@@ -1,6 +1,6 @@
############################################################################
#
# Copyright (c) 2015 ECL Development Team. All rights reserved.
# Copyright (c) 2015-2018 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -30,14 +30,10 @@
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE lib__ecl__EKF__tests__base
MAIN base
STACK_MAIN 4096
COMPILE_FLAGS
SRCS
base.cpp
DEPENDS
platforms__common
)
add_executable(ecl_EKF_tests_base base.cpp)
target_link_libraries(ecl_EKF_tests_base ecl_EKF)
add_test(NAME ecl_EKF_tests_base
COMMAND ecl_EKF_tests_base
)
+12 -15
View File
@@ -37,22 +37,20 @@
* Tests for the estimator base class
*/
#include <EKF/ekf.h>
#include <cstdio>
#include <random>
#include "../../estimator_base.h"
extern "C" __EXPORT int base_main(int argc, char *argv[]);
int base_main(int argc, char *argv[])
int main(int argc, char *argv[])
{
EstimatorBase *base = new EstimatorBase();
Ekf *base = new Ekf();
// Test1: feed in fake imu data and check if delta angles are summed correclty
float delta_vel[3] = { 0.002f, 0.002f, 0.002f};
float delta_ang[3] = { -0.1f, 0.2f, 0.3f};
uint32_t time_usec = 1000;
// simulate 400 Hz imu rate, filter should downsample to 100Hz
// feed in 2 seconds of data
for (int i = 0; i < 800; i++) {
@@ -95,7 +93,7 @@ int base_main(int argc, char *argv[])
time_usec = 100000;
for (int i = 0; i < 100; i++) {
base->setBaroData(time_usec, &baro);
base->setBaroData(time_usec, baro);
baro += 10.0f;
time_usec += 20000;
}
@@ -126,25 +124,24 @@ int base_main(int argc, char *argv[])
timer += (imu_sample_period + distribution(generator));
if ((timer - timer_last) > 70000) {
base->setAirspeedData(timer, &airspeed);
base->setAirspeedData(timer, airspeed, 1.0f);
}
gps.time_usec = timer;
gps.time_usec_vel = timer;
base->setIMUData(timer, timer - timer_last, timer - timer_last, delta_ang, delta_vel);
base->setMagData(timer, mag);
base->setBaroData(timer, &baro);
base->setBaroData(timer, baro);
base->setGpsData(timer, &gps);
base->print_imu_avg_time();
//base->print_imu_avg_time();
timer_last = timer;
}
base->printStoredIMU();
base->printStoredBaro();
base->printStoredMag();
base->printStoredGps();
//base->printStoredIMU();
//base->printStoredBaro();
//base->printStoredMag();
//base->printStoredGps();
return 0;
}
+73
View File
@@ -0,0 +1,73 @@
############################################################################
#
# Copyright (c) 2015-2018 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name ECL nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
if(EKF_PYTHON_TESTS)
add_custom_target(ecl_EKF_pytest
COMMAND env PYTHONPATH=${CMAKE_BINARY_DIR}/EKF/swig/python ${CMAKE_CURRENT_SOURCE_DIR}/ekf_test.py --verbose
DEPENDS ecl_EKF _ecl_EKF
USES_TERMINAL
)
add_custom_target(ecl_EKF_pytest-quick
COMMAND env PYTHONPATH=${CMAKE_BINARY_DIR}/EKF/swig/python ${CMAKE_CURRENT_SOURCE_DIR}/ekf_test.py --quick --verbose
DEPENDS ecl_EKF _ecl_EKF
USES_TERMINAL
)
add_custom_target(ecl_EKF_pytest-benchmark
COMMAND env PYTHONPATH=${CMAKE_BINARY_DIR}/EKF/swig/python ${CMAKE_CURRENT_SOURCE_DIR}/ekf_test.py --benchmark
DEPENDS ecl_EKF _ecl_EKF
USES_TERMINAL
)
# requires python3-tk
add_custom_target(ecl_EKF_pytest-plots
COMMAND env PYTHONPATH=${CMAKE_BINARY_DIR}/EKF/swig/python ${CMAKE_CURRENT_SOURCE_DIR}/ekf_test.py --plots
DEPENDS ecl_EKF _ecl_EKF
USES_TERMINAL
)
add_custom_target(ecl_EKF_pytest-lint
COMMAND env PYTHONPATH=${CMAKE_BINARY_DIR}/EKF/swig/python ${CMAKE_CURRENT_SOURCE_DIR}/lint.py
DEPENDS ecl_EKF _ecl_EKF
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
USES_TERMINAL
)
# ctest entry
add_test(NAME ecl_EKF_pytest_run
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ecl_EKF_pytest-quick
)
endif()
@@ -37,7 +37,7 @@
In order to run the tests, make sure to compile the ecl library including the
SWIG bindings, e.g. by running
cmake -DPythonTests=1 ../EKF && make pytest-quick
cmake -DEKF_PYTHON_TESTS=ON .. && make ecl_EKF_pytest-quick
from your build directory.
@@ -45,10 +45,10 @@ from datetime import datetime
CHECKERS = [
['pep8', '.'],
['pep8', './ekf_test'],
['pep8', './lint'],
['pylint', './lint', '--reports=n', '--score=n'],
['pylint', './ekf_test', '--reports=n', '--score=n'],
['pep8', './ekf_test.py'],
['pep8', './lint.py'],
['pylint', './lint.py', '--reports=n', '--score=n'],
['pylint', './ekf_test.py', '--reports=n', '--score=n'],
['pylint', './plot_utils.py', '--reports=n', '--score=n'],
['pylint', './test_altitude.py', '--reports=n', '--score=n'],
['pylint', './test_basics.py', '--reports=n', '--score=n'],
+7 -7
View File
@@ -49,7 +49,7 @@ from hypothesis import given
from hypothesis import example
from hypothesis import strategies as st
from test_utils import ecl
from test_utils import ecl_EKF
from test_utils import update_sensors
from test_utils import float_array
from test_utils import initialized_ekf
@@ -61,10 +61,10 @@ from test_utils import initialized_ekf
def test_accel_z_bias_converges(z_bias):
"""Make sure the accelerometer bias in z-direction is estimated correctly
"""
ekf = ecl.Ekf()
ekf = ecl_EKF.Ekf()
time_usec = 1000
dt_usec = ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000
dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000
# Run for a while
n_samples = 10000
@@ -84,7 +84,7 @@ def test_accel_z_bias_converges(z_bias):
dt_usec,
accel=float_array([0.0,
0.0,
-ecl.one_g + z_bias]))
-ecl_EKF.one_g + z_bias]))
ekf.update()
time_usec += dt_usec
@@ -136,7 +136,7 @@ def test_converges_to_baro_altitude(altitude):
# Due to hypothesis not interacting with pytest, cannot use fixture here
ekf, time_usec = initialized_ekf()
dt_usec = ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000
dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000
# No samples, half are used for ramping up / down to the altitude
n_samples = 200
@@ -166,9 +166,9 @@ def test_converges_to_baro_altitude(altitude):
dt_usec,
accel=float_array([0,
0,
-ecl.one_g - rampup_accel
-ecl_EKF.one_g - rampup_accel
if i < n_samples // 4
else -ecl.one_g + rampup_accel]),
else -ecl_EKF.one_g + rampup_accel]),
baro_data=current_state.alt)
ekf.update()
+2 -2
View File
@@ -42,7 +42,7 @@ from __future__ import absolute_import
import pytest
from test_utils import ecl
from test_utils import ecl_EKF
# Pylint does not like pytest fixtures, disable the warning
# pylint: disable=redefined-outer-name
@@ -93,7 +93,7 @@ def test_status_on_imu_mag_baro(initialized_ekf):
def test_converges_to_zero():
"""Make sure the EKF with zero inputs converges to / stays at zero
"""
ekf = ecl.Ekf()
ekf = ecl_EKF.Ekf()
time_usec = 1000
dt_usec = 5000
+16 -16
View File
@@ -44,14 +44,14 @@ import pytest
from hypothesis import given
from hypothesis import strategies as st
from test_utils import ecl
from test_utils import ecl_EKF
from test_utils import float_array
@pytest.mark.parametrize("dt_usec, downsampling_factor", [
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 3, 3),
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 2, 2),
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000, 1),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 3, 3),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 2, 2),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000, 1),
])
@given(accel_x=st.floats(-5, 5),
accel_y=st.floats(-5, 5),
@@ -71,7 +71,7 @@ def test_imu_input(dt_usec, downsampling_factor, accel_x, accel_y, accel_z):
accel_y,
accel_z]) * dt_usec / 1e6
ekf = ecl.Ekf()
ekf = ecl_EKF.Ekf()
# Run to accumulate buffer (choose sample after downsampling)
for _ in range(20 * downsampling_factor):
time_usec += dt_usec
@@ -94,14 +94,14 @@ def test_imu_input(dt_usec, downsampling_factor, accel_x, accel_y, accel_z):
@pytest.mark.parametrize("dt_usec, expected_dt_usec", [
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 3,
ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 2,
ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000,
ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 * 2,
ecl.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 * 2),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 3,
ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 // 2,
ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000,
ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000),
(ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 * 2,
ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000 * 2),
(500 * 1000,
500 * 1000)
])
@@ -115,7 +115,7 @@ def test_imu_sampling(dt_usec, expected_dt_usec):
time_usec = 0
delta_ang = float_array([0, 0, 0])
delta_vel = float_array([0, 0, 0])
ekf = ecl.Ekf()
ekf = ecl_EKF.Ekf()
for _ in range(100):
time_usec += dt_usec
ekf.set_imu_data(time_usec,
@@ -126,9 +126,9 @@ def test_imu_sampling(dt_usec, expected_dt_usec):
imu_sample = ekf.get_imu_sample_delayed()
assert imu_sample.delta_ang_dt == pytest.approx(
expected_dt_usec / 1e6, abs=1e-6)
expected_dt_usec / 1e6, abs=1e-5)
assert imu_sample.delta_vel_dt == pytest.approx(
expected_dt_usec / 1e6, abs=1e-6)
expected_dt_usec / 1e6, abs=1e-5)
# Make sure the timestamp of the last sample is a small positive multiple
# of the period away from now
assert (time_usec - imu_sample.time_us) >= 0
+3 -3
View File
@@ -44,7 +44,7 @@ import numpy as np
import pytest
try:
import ecl # pylint: disable=import-error
import ecl_EKF # pylint: disable=import-error
except ImportError:
print("ImportError: ecl library cannot be found."
" Make sure to compile ecl with Python bindings "
@@ -62,7 +62,7 @@ def float_array(inp):
def update_sensors(ekf, # pylint: disable=too-many-arguments
time_usec,
dt_usec,
accel=float_array([0.0, 0.0, -ecl.one_g]),
accel=float_array([0.0, 0.0, -ecl_EKF.one_g]),
ang_vel=float_array([0.0, 0.0, 0.0]),
mag_data=float_array([1.0, 0.0, 0.0]),
baro_data=0.0):
@@ -83,7 +83,7 @@ def update_sensors(ekf, # pylint: disable=too-many-arguments
def initialized_ekf():
"""Provides an initialized ekf, ready to go
"""
ekf = ecl.Ekf()
ekf = ecl_EKF.Ekf()
time_usec = 1000
dt_usec = 5000
+7 -11
View File
@@ -1,6 +1,6 @@
############################################################################
#
# Copyright (c) 2015 ECL Development Team. All rights reserved.
# Copyright (c) 2015-2018 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -30,14 +30,10 @@
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE lib__ecl__EKF__tests__ringbuffer
MAIN ringbuffer
STACK_MAIN 4096
COMPILE_FLAGS
SRCS
ringbuffer.cpp
DEPENDS
platforms__common
)
add_executable(ecl_EKF_tests_ringbuffer ringbuffer.cpp)
target_link_libraries(ecl_EKF_tests_ringbuffer ecl_EKF)
add_test(NAME ecl_EKF_tests_ringbuffer
COMMAND ecl_EKF_tests_ringbuffer
)
+15 -16
View File
@@ -41,16 +41,14 @@
#include <stdint.h>
#include <cassert>
#include "../../RingBuffer.h"
extern "C" __EXPORT int ringbuffer_main(int argc, char *argv[]);
#include <EKF/RingBuffer.h>
struct sample {
uint64_t time_us;
float data[3];
};
int ringbuffer_main(int argc, char *argv[])
int main(int argc, char *argv[])
{
sample x;
x.time_us = 1000000;
@@ -67,10 +65,11 @@ int ringbuffer_main(int argc, char *argv[])
// Test1: false buffer allocation
bool initialised = false;
RingBuffer<sample> buffer;
initialised = buffer.allocate(-1);
assert(initialised == false);
initialised = buffer.allocate(0);
assert(initialised == false);
//initialised = buffer.allocate(-1);
//assert(initialised == false);
//initialised = buffer.allocate(0);
//assert(initialised == false);
// Test2: good initialisation
initialised = buffer.allocate(3);
@@ -79,7 +78,7 @@ int ringbuffer_main(int argc, char *argv[])
// Test3: pushing data into ringbuffer
buffer.push(x);
assert(buffer.get_newest().time_us == x.time_us);
assert(buffer.get_oldest().time_us == 0);
//assert(buffer.get_oldest().time_us == 0);
buffer.push(y);
buffer.push(z);
assert(buffer.get_newest().time_us == z.time_us);
@@ -90,18 +89,18 @@ int ringbuffer_main(int argc, char *argv[])
// this should return false, because there is no data older than t = 0
assert(buffer.pop_first_older_than(0, &pop) == false);
assert(buffer.pop_first_older_than(x.time_us + 1 , &pop) == true);
assert(buffer.pop_first_older_than(x.time_us + 1, &pop) == true);
assert(pop.time_us == x.time_us);
assert(buffer.pop_first_older_than(y.time_us + 100 , &pop) == true);
assert(buffer.pop_first_older_than(y.time_us + 100, &pop) == true);
assert(pop.time_us == y.time_us);
assert(buffer.pop_first_older_than(z.time_us + 100 , &pop) == true);
assert(buffer.pop_first_older_than(z.time_us + 100, &pop) == true);
assert(pop.time_us == z.time_us);
// Test 4: Bigger buffer, redo Test3
buffer.allocate(10);
buffer.push(x);
assert(buffer.get_newest().time_us == x.time_us);
assert(buffer.get_oldest().time_us == 0);
//assert(buffer.get_oldest().time_us == 0);
buffer.push(y);
buffer.push(z);
assert(buffer.get_newest().time_us == z.time_us);
@@ -110,11 +109,11 @@ int ringbuffer_main(int argc, char *argv[])
// buffer will not accept measurement will is older than 0.5 seconds
assert(buffer.pop_first_older_than(600000, &pop) == false);
assert(buffer.pop_first_older_than(x.time_us + 1 , &pop) == true);
assert(buffer.pop_first_older_than(x.time_us + 1, &pop) == true);
assert(pop.time_us == x.time_us);
assert(buffer.pop_first_older_than(y.time_us + 100 , &pop) == true);
assert(buffer.pop_first_older_than(y.time_us + 100, &pop) == true);
assert(pop.time_us == y.time_us);
assert(buffer.pop_first_older_than(z.time_us + 100 , &pop) == true);
assert(buffer.pop_first_older_than(z.time_us + 100, &pop) == true);
assert(pop.time_us == z.time_us);
return 0;
Vendored
+46 -23
View File
@@ -1,10 +1,10 @@
pipeline {
agent none
stages {
stage('build') {
stage('Build') {
parallel {
stage('build') {
stage('Linux GCC') {
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
}
@@ -24,7 +24,7 @@ pipeline {
}
}
stage('build clang') {
stage('Linux Clang') {
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
CC = 'clang'
@@ -46,24 +46,6 @@ pipeline {
}
}
stage('pytest') {
agent {
docker {
image 'px4io/px4-dev-ecl:2018-04-22'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'make distclean'
sh 'make'
sh 'ccache -s'
//sh 'RUN_PYTEST=1 ./build.sh'
sh 'make distclean'
}
}
stage('OSX') {
agent {
node {
@@ -81,10 +63,51 @@ pipeline {
sh 'ccache -s'
sh 'make distclean'
}
}
}
}
} // parallel
} // stage Build
stage('Test') {
parallel {
stage('EKF pytest') {
agent {
docker {
image 'px4io/px4-dev-ecl:2018-04-22'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'make distclean'
sh 'make test_EKF'
sh 'ccache -s'
sh 'make distclean'
}
}
stage('test') {
agent {
docker {
image 'px4io/px4-dev-ecl:2018-04-22'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'make distclean'
sh 'make test'
sh 'ccache -s'
sh 'make distclean'
}
}
} // parallel
}
}
environment {
+16 -5
View File
@@ -78,14 +78,27 @@ SRC_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
define cmake-build
+@$(eval BUILD_DIR = $(SRC_DIR)/build/$@$(BUILD_DIR_SUFFIX))
+@if [ $(PX4_CMAKE_GENERATOR) = "Ninja" ] && [ -e $(BUILD_DIR)/Makefile ]; then rm -rf $(BUILD_DIR); fi
+@if [ ! -e $(BUILD_DIR)/CMakeCache.txt ]; then mkdir -p $(BUILD_DIR) && cd $(BUILD_DIR) && cmake $(2) -G"$(PX4_CMAKE_GENERATOR)" $(CMAKE_ARGS) || (rm -rf $(BUILD_DIR)); fi
+@if [ ! -e $(BUILD_DIR)/CMakeCache.txt ]; then mkdir -p $(BUILD_DIR) && cd $(BUILD_DIR) && cmake $(2) -G"$(PX4_CMAKE_GENERATOR)" $(CMAKE_ARGS) $(3) || (rm -rf $(BUILD_DIR)); fi
+@(cd $(BUILD_DIR) && $(PX4_MAKE) $(PX4_MAKE_ARGS) $(ARGS))
endef
all:
$(call cmake-build,$@,$(SRC_DIR))
@$(call cmake-build,$@,$(SRC_DIR))
# Testing
# --------------------------------------------------------------------
.PHONY: test_build test test_EKF
test_build:
@$(call cmake-build,$@,$(SRC_DIR), "-DEKF_PYTHON_TESTS=ON")
test: test_build
@cmake --build $(SRC_DIR)/build/test_build --target check
test_EKF: test_build
@cmake --build $(SRC_DIR)/build/test_build --target ecl_EKF_pytest-quick
# Cleanup
# --------------------------------------------------------------------
@@ -96,6 +109,4 @@ clean:
distclean:
@git clean -ff -x -d .