Move motion::dual_move_ramp into the separate motion::rampgen test
- Remove motion::dual_move_ramp from the Catch2 tests and reimplement it as a minimal c++ program for the ramp validation. - Add a skeleton python validator to check the ramp output - Use test "fixtures" to ensure the rampgen is run (both as a test, and to generate output) when the test_motion_ramp.py is requested.pull/87/head
parent
f37c9e363c
commit
89ab29dbde
|
|
@ -1,19 +1,25 @@
|
||||||
# define the test executable
|
# common include and source directories
|
||||||
add_executable(
|
set(include_common ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal)
|
||||||
motion_tests
|
set(source_common
|
||||||
${CMAKE_SOURCE_DIR}/src/modules/motion.cpp
|
${CMAKE_SOURCE_DIR}/src/modules/motion.cpp ${CMAKE_SOURCE_DIR}/src/modules/speed_table.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/modules/speed_table.cpp
|
${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp ${MODULES_STUBS_DIR}/stub_gpio.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp
|
${MODULES_STUBS_DIR}/stub_shr16.cpp ${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||||
${MODULES_STUBS_DIR}/stub_gpio.cpp
|
)
|
||||||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
|
||||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
|
||||||
test_motion.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# define required search paths
|
# general motion tests
|
||||||
target_include_directories(
|
add_executable(motion_tests ${source_common} test_motion.cpp)
|
||||||
motion_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal
|
target_include_directories(motion_tests PUBLIC ${include_common})
|
||||||
)
|
|
||||||
|
|
||||||
# tell build system about the test case
|
|
||||||
add_catch_test(motion_tests)
|
add_catch_test(motion_tests)
|
||||||
|
|
||||||
|
# ramp generation tests
|
||||||
|
add_executable(rampgen ${source_common} rampgen.cpp)
|
||||||
|
target_include_directories(rampgen PUBLIC ${include_common})
|
||||||
|
|
||||||
|
add_test(NAME motion::rampgen COMMAND rampgen ramp_data.txt)
|
||||||
|
add_test(NAME motion::test_motion_ramp COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test_motion_ramp.py
|
||||||
|
ramp_data.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
# define the ramp_data fixture to chain tests
|
||||||
|
set_tests_properties(motion::test_motion_ramp PROPERTIES FIXTURES_REQUIRED motion::ramp_data)
|
||||||
|
set_tests_properties(motion::rampgen PROPERTIES FIXTURES_SETUP motion::ramp_data)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <sysexits.h>
|
||||||
|
|
||||||
|
#include "motion.h"
|
||||||
|
using namespace modules::motion;
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
const char *output = argv[1];
|
||||||
|
if (!argv[1]) {
|
||||||
|
fprintf(stderr, "Usage: %s <output>\n", argv[0]);
|
||||||
|
return EX_USAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *fd = fopen(output, "w");
|
||||||
|
if (!fd) {
|
||||||
|
fprintf(stderr, "%s: can't open output file %s: ", argv[0], output);
|
||||||
|
perror(NULL);
|
||||||
|
return EX_OSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// common settings
|
||||||
|
const int idlerSteps = 100;
|
||||||
|
const int selectorSteps = 80;
|
||||||
|
const int maxFeedRate = 1000;
|
||||||
|
|
||||||
|
for (int accel = 2000; accel <= 50000; accel *= 2) {
|
||||||
|
// first axis using nominal values
|
||||||
|
motion.SetPosition(Idler, 0);
|
||||||
|
motion.SetAcceleration(Idler, accel);
|
||||||
|
motion.PlanMoveTo(Idler, idlerSteps, maxFeedRate);
|
||||||
|
|
||||||
|
fprintf(fd, "[{\"steps\": %d, \"accel\": %d, \"maxrate\": %d}, ",
|
||||||
|
idlerSteps, accel, maxFeedRate);
|
||||||
|
|
||||||
|
// second axis finishes slightly sooner at triple acceleration to maximize the
|
||||||
|
// aliasing effects
|
||||||
|
int accel_3 = accel * 3;
|
||||||
|
motion.SetPosition(Selector, 0);
|
||||||
|
motion.SetAcceleration(Selector, accel_3);
|
||||||
|
motion.PlanMoveTo(Selector, selectorSteps, maxFeedRate);
|
||||||
|
|
||||||
|
fprintf(fd, "{\"steps\": %d, \"accel\": %d, \"maxrate\": %d}]\n",
|
||||||
|
selectorSteps, accel_3, maxFeedRate);
|
||||||
|
|
||||||
|
// step and output time, interval and positions
|
||||||
|
unsigned long ts = 0;
|
||||||
|
st_timer_t next;
|
||||||
|
do {
|
||||||
|
next = motion.Step();
|
||||||
|
pos_t pos_idler = motion.CurPosition(Idler);
|
||||||
|
pos_t pos_selector = motion.CurPosition(Selector);
|
||||||
|
|
||||||
|
fprintf(fd, "%lu %u %d %d\n", ts, next, pos_idler, pos_selector);
|
||||||
|
|
||||||
|
ts += next;
|
||||||
|
} while (next);
|
||||||
|
fprintf(fd, "\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return EX_OK;
|
||||||
|
}
|
||||||
|
|
@ -164,46 +164,3 @@ TEST_CASE("motion::triple_move", "[motion]") {
|
||||||
REQUIRE(motion.Position(Selector) == 20);
|
REQUIRE(motion.Position(Selector) == 20);
|
||||||
REQUIRE(motion.Position(Pulley) == 30);
|
REQUIRE(motion.Position(Pulley) == 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("motion::dual_move_ramp", "[motion]") {
|
|
||||||
// TODO: output ramps still to be checked
|
|
||||||
const int idlerSteps = 100;
|
|
||||||
const int selectorSteps = 80;
|
|
||||||
const int maxFeedRate = 1000;
|
|
||||||
|
|
||||||
for (int accel = 2000; accel <= 50000; accel *= 2) {
|
|
||||||
REQUIRE(motion.QueueEmpty());
|
|
||||||
|
|
||||||
// first axis using nominal values
|
|
||||||
motion.SetPosition(Idler, 0);
|
|
||||||
motion.SetAcceleration(Idler, accel);
|
|
||||||
motion.PlanMoveTo(Idler, idlerSteps, maxFeedRate);
|
|
||||||
|
|
||||||
// second axis finishes slightly sooner at triple acceleration to maximize the
|
|
||||||
// aliasing effects
|
|
||||||
motion.SetPosition(Selector, 0);
|
|
||||||
motion.SetAcceleration(Selector, accel * 3);
|
|
||||||
motion.PlanMoveTo(Selector, selectorSteps, maxFeedRate);
|
|
||||||
|
|
||||||
// step and output time, interval and positions
|
|
||||||
unsigned long ts = 0;
|
|
||||||
st_timer_t next;
|
|
||||||
do {
|
|
||||||
next = motion.Step();
|
|
||||||
pos_t pos_idler = motion.CurPosition(Idler);
|
|
||||||
pos_t pos_selector = motion.CurPosition(Selector);
|
|
||||||
|
|
||||||
printf("%lu %u %d %d\n", ts, next, pos_idler, pos_selector);
|
|
||||||
|
|
||||||
ts += next;
|
|
||||||
} while (next);
|
|
||||||
printf("\n\n");
|
|
||||||
|
|
||||||
// check queue status
|
|
||||||
REQUIRE(motion.QueueEmpty());
|
|
||||||
|
|
||||||
// check final position
|
|
||||||
REQUIRE(motion.Position(Idler) == idlerSteps);
|
|
||||||
REQUIRE(motion.Position(Selector) == selectorSteps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
exit(0)
|
||||||
Loading…
Reference in New Issue