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
|
||||
add_executable(
|
||||
motion_tests
|
||||
${CMAKE_SOURCE_DIR}/src/modules/motion.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/speed_table.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp
|
||||
${MODULES_STUBS_DIR}/stub_gpio.cpp
|
||||
${MODULES_STUBS_DIR}/stub_shr16.cpp
|
||||
${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
test_motion.cpp
|
||||
)
|
||||
# common include and source directories
|
||||
set(include_common ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal)
|
||||
set(source_common
|
||||
${CMAKE_SOURCE_DIR}/src/modules/motion.cpp ${CMAKE_SOURCE_DIR}/src/modules/speed_table.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/pulse_gen.cpp ${MODULES_STUBS_DIR}/stub_gpio.cpp
|
||||
${MODULES_STUBS_DIR}/stub_shr16.cpp ${MODULES_STUBS_DIR}/stub_tmc2130.cpp
|
||||
)
|
||||
|
||||
# define required search paths
|
||||
target_include_directories(
|
||||
motion_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal
|
||||
)
|
||||
|
||||
# tell build system about the test case
|
||||
# general motion tests
|
||||
add_executable(motion_tests ${source_common} test_motion.cpp)
|
||||
target_include_directories(motion_tests PUBLIC ${include_common})
|
||||
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(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