Tune Feed to FINDA state machine and its unit test
so that it works as expected Still, there is a task of resetting all of the state machines just for the next unit test to be run.pull/26/head
parent
f0a042c1b6
commit
b8f6bc9a4e
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../modules/finda.h"
|
#include "../modules/finda.h"
|
||||||
#include "../modules/globals.h"
|
#include "../modules/globals.h"
|
||||||
#include "../modules/idler.h"
|
#include "../modules/idler.h"
|
||||||
|
#include "../modules/selector.h"
|
||||||
#include "../modules/leds.h"
|
#include "../modules/leds.h"
|
||||||
#include "../modules/motion.h"
|
#include "../modules/motion.h"
|
||||||
#include "../modules/permanent_storage.h"
|
#include "../modules/permanent_storage.h"
|
||||||
|
|
@ -15,20 +16,23 @@ namespace mi = modules::idler;
|
||||||
namespace ml = modules::leds;
|
namespace ml = modules::leds;
|
||||||
namespace mb = modules::buttons;
|
namespace mb = modules::buttons;
|
||||||
namespace mg = modules::globals;
|
namespace mg = modules::globals;
|
||||||
|
namespace ms = modules::selector;
|
||||||
|
|
||||||
void FeedToFinda::Reset(bool feedPhaseLimited) {
|
void FeedToFinda::Reset(bool feedPhaseLimited) {
|
||||||
state = EngagingIdler;
|
state = EngagingIdler;
|
||||||
this->feedPhaseLimited = feedPhaseLimited;
|
this->feedPhaseLimited = feedPhaseLimited;
|
||||||
mi::idler.Engage(mg::globals.ActiveSlot());
|
mi::idler.Engage(mg::globals.ActiveSlot());
|
||||||
|
// We can't get any FINDA readings if the selector is at the wrong spot - move it accordingly if necessary
|
||||||
|
ms::selector.MoveToSlot(mg::globals.ActiveSlot());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FeedToFinda::Step() {
|
bool FeedToFinda::Step() {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case EngagingIdler:
|
case EngagingIdler:
|
||||||
if (mi::idler.Engaged()) {
|
if (mi::idler.Engaged() && ms::selector.Slot() == mg::globals.ActiveSlot()) {
|
||||||
state = PushingFilament;
|
state = PushingFilament;
|
||||||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::blink0);
|
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::blink0);
|
||||||
mm::motion.PlanMove(feedPhaseLimited ? 1500 : 65535, 0, 0, 4000, 0, 0); //@@TODO constants
|
mm::motion.PlanMove(feedPhaseLimited ? 1500 : 32767, 0, 0, 4000, 0, 0); //@@TODO constants
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case PushingFilament:
|
case PushingFilament:
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@ bool Motion::StallGuard(Axis axis) { return false; }
|
||||||
|
|
||||||
void Motion::ClearStallGuardFlag(Axis axis) {}
|
void Motion::ClearStallGuardFlag(Axis axis) {}
|
||||||
|
|
||||||
void Motion::PlanMove(uint16_t pulley, uint16_t idler, uint16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed) {}
|
void Motion::PlanMove(int16_t pulley, int16_t idler, int16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed) {}
|
||||||
|
|
||||||
|
void Motion::PlanMove(Axis axis, int16_t delta, uint16_t feedrate) {}
|
||||||
|
|
||||||
void Motion::Home(Axis axis, bool direction) {}
|
void Motion::Home(Axis axis, bool direction) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,13 @@ public:
|
||||||
|
|
||||||
/// Enqueue move of a specific motor/axis into planner buffer
|
/// Enqueue move of a specific motor/axis into planner buffer
|
||||||
/// @param pulley, idler, selector - target coords
|
/// @param pulley, idler, selector - target coords
|
||||||
void PlanMove(uint16_t pulley, uint16_t idler, uint16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed);
|
void PlanMove(int16_t pulley, int16_t idler, int16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed);
|
||||||
|
|
||||||
|
/// Enqueue a single axis move in steps starting and ending at zero speed with maximum feedrate
|
||||||
|
/// @param axis axis affected
|
||||||
|
/// @param delta number of steps in either direction
|
||||||
|
/// @param feedrate maximum feedrate/speed after acceleration
|
||||||
|
void PlanMove(Axis axis, int16_t delta, uint16_t feedrate);
|
||||||
|
|
||||||
/// Enqueue performing of homing of an axis
|
/// Enqueue performing of homing of an axis
|
||||||
/// @@TODO
|
/// @@TODO
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,22 @@ bool WhileCondition(logic::FeedToFinda &ff, COND cond, uint32_t maxLoops = 5000)
|
||||||
|
|
||||||
TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
|
TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
|
||||||
using namespace logic;
|
using namespace logic;
|
||||||
FeedToFinda ff;
|
|
||||||
main_loop();
|
// no buttons involved ;)
|
||||||
|
hal::adc::TADCData noButtons({ 0 });
|
||||||
|
hal::adc::ReinitADC(0, std::move(noButtons), 1);
|
||||||
|
|
||||||
|
// finda OFF
|
||||||
|
hal::adc::TADCData findaOFF({ 0 });
|
||||||
|
hal::adc::ReinitADC(1, std::move(findaOFF), 1);
|
||||||
|
|
||||||
// let's assume we have the filament NOT loaded and active slot 0
|
// let's assume we have the filament NOT loaded and active slot 0
|
||||||
modules::globals::globals.SetFilamentLoaded(false);
|
modules::globals::globals.SetFilamentLoaded(false);
|
||||||
modules::globals::globals.SetActiveSlot(0);
|
modules::globals::globals.SetActiveSlot(0);
|
||||||
|
|
||||||
|
FeedToFinda ff;
|
||||||
|
main_loop();
|
||||||
|
|
||||||
// restart the automaton
|
// restart the automaton
|
||||||
ff.Reset(false);
|
ff.Reset(false);
|
||||||
|
|
||||||
|
|
@ -46,6 +55,8 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
|
||||||
// check if the idler and selector have the right command
|
// check if the idler and selector have the right command
|
||||||
CHECK(modules::motion::axes[modules::motion::Idler].targetPos == 0); // @@TODO constants
|
CHECK(modules::motion::axes[modules::motion::Idler].targetPos == 0); // @@TODO constants
|
||||||
CHECK(modules::motion::axes[modules::motion::Selector].targetPos == 0); // @@TODO constants
|
CHECK(modules::motion::axes[modules::motion::Selector].targetPos == 0); // @@TODO constants
|
||||||
|
CHECK(modules::motion::axes[modules::motion::Idler].enabled == true); // @@TODO constants
|
||||||
|
CHECK(modules::motion::axes[modules::motion::Selector].enabled == true); // @@TODO constants
|
||||||
|
|
||||||
// engaging idler
|
// engaging idler
|
||||||
REQUIRE(WhileCondition(
|
REQUIRE(WhileCondition(
|
||||||
|
|
@ -53,15 +64,15 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
|
||||||
[&]() { return !modules::idler::idler.Engaged(); },
|
[&]() { return !modules::idler::idler.Engaged(); },
|
||||||
5000));
|
5000));
|
||||||
|
|
||||||
// idler engaged, we'll start pushing filament
|
// idler engaged, selector in position, we'll start pushing filament
|
||||||
REQUIRE(ff.State() == FeedToFinda::PushingFilament);
|
REQUIRE(ff.State() == FeedToFinda::PushingFilament);
|
||||||
// at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test)
|
// at least at the beginning the LED should shine green (it should be blinking, but this mode has been already verified in the LED's unit test)
|
||||||
REQUIRE(modules::leds::leds.LedOn(modules::globals::globals.ActiveSlot(), modules::leds::Color::green));
|
REQUIRE(modules::leds::leds.LedOn(modules::globals::globals.ActiveSlot(), modules::leds::Color::green));
|
||||||
|
|
||||||
// now let the filament be pushed into the FINDA - do 500 steps without triggering the condition
|
// now let the filament be pushed into the FINDA - do 500 steps without triggering the condition
|
||||||
// and then let the simulated ADC channel 1 create a FINDA switch
|
// and then let the simulated ADC channel 1 create a FINDA switch
|
||||||
hal::adc::TADCData switchFindaOn({ 0, 600, 700, 800, 900 });
|
hal::adc::TADCData switchFindaOn({ 600, 700, 800, 900 });
|
||||||
hal::adc::ReinitADC(1, std::move(switchFindaOn), 100);
|
hal::adc::ReinitADC(1, std::move(switchFindaOn), 1);
|
||||||
REQUIRE(WhileCondition(
|
REQUIRE(WhileCondition(
|
||||||
ff,
|
ff,
|
||||||
[&]() { return ff.State() == FeedToFinda::PushingFilament; },
|
[&]() { return ff.State() == FeedToFinda::PushingFilament; },
|
||||||
|
|
@ -91,13 +102,25 @@ TEST_CASE("feed_to_finda::feed_phase_unlimited", "[feed_to_finda]") {
|
||||||
|
|
||||||
TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") {
|
TEST_CASE("feed_to_finda::FINDA_failed", "[feed_to_finda]") {
|
||||||
using namespace logic;
|
using namespace logic;
|
||||||
FeedToFinda ff;
|
|
||||||
main_loop();
|
// This is a problem - how to reset all the state machines at once?
|
||||||
|
// May be add an #ifdef unit_tests and a reset function for each of the automatons
|
||||||
|
|
||||||
|
// no buttons involved ;)
|
||||||
|
hal::adc::TADCData noButtons({ 0 });
|
||||||
|
hal::adc::ReinitADC(0, std::move(noButtons), 1);
|
||||||
|
|
||||||
|
// finda OFF
|
||||||
|
hal::adc::TADCData findaOFF({ 0 });
|
||||||
|
hal::adc::ReinitADC(1, std::move(findaOFF), 1);
|
||||||
|
|
||||||
// let's assume we have the filament NOT loaded and active slot 0
|
// let's assume we have the filament NOT loaded and active slot 0
|
||||||
modules::globals::globals.SetFilamentLoaded(false);
|
modules::globals::globals.SetFilamentLoaded(false);
|
||||||
modules::globals::globals.SetActiveSlot(0);
|
modules::globals::globals.SetActiveSlot(0);
|
||||||
|
|
||||||
|
FeedToFinda ff;
|
||||||
|
main_loop();
|
||||||
|
|
||||||
// restart the automaton - we want the limited version of the feed
|
// restart the automaton - we want the limited version of the feed
|
||||||
ff.Reset(true);
|
ff.Reset(true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,24 @@
|
||||||
#include "../../../../src/modules/globals.h"
|
#include "../../../../src/modules/globals.h"
|
||||||
#include "../../../../src/modules/idler.h"
|
#include "../../../../src/modules/idler.h"
|
||||||
#include "../../../../src/modules/leds.h"
|
#include "../../../../src/modules/leds.h"
|
||||||
|
#include "../../../../src/modules/motion.h"
|
||||||
#include "../../../../src/modules/permanent_storage.h"
|
#include "../../../../src/modules/permanent_storage.h"
|
||||||
#include "../../../../src/modules/selector.h"
|
#include "../../../../src/modules/selector.h"
|
||||||
|
|
||||||
logic::CommandBase *currentCommand = nullptr;
|
logic::CommandBase *currentCommand = nullptr;
|
||||||
|
|
||||||
// just like in the real FW, step all the known automata
|
// just like in the real FW, step all the known automata
|
||||||
|
uint16_t tmpTiming = 0;
|
||||||
|
|
||||||
void main_loop() {
|
void main_loop() {
|
||||||
modules::buttons::buttons.Step(hal::adc::ReadADC(0));
|
modules::buttons::buttons.Step(hal::adc::ReadADC(0));
|
||||||
modules::leds::leds.Step(1);
|
modules::leds::leds.Step(tmpTiming);
|
||||||
modules::finda::finda.Step(1);
|
modules::finda::finda.Step(tmpTiming);
|
||||||
modules::fsensor::fsensor.Step(1);
|
modules::fsensor::fsensor.Step(tmpTiming);
|
||||||
modules::idler::idler.Step();
|
modules::idler::idler.Step();
|
||||||
modules::selector::selector.Step();
|
modules::selector::selector.Step();
|
||||||
|
modules::motion::motion.Step();
|
||||||
if (currentCommand)
|
if (currentCommand)
|
||||||
currentCommand->Step();
|
currentCommand->Step();
|
||||||
|
++tmpTiming;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ namespace modules {
|
||||||
namespace motion {
|
namespace motion {
|
||||||
|
|
||||||
Motion motion;
|
Motion motion;
|
||||||
AxisSim axes[3];
|
AxisSim axes[3] = {
|
||||||
|
{ 0, 0, false, false, false },
|
||||||
|
{ 0, 0, false, false, false },
|
||||||
|
{ 0, 0, false, false, false },
|
||||||
|
};
|
||||||
|
|
||||||
void Motion::InitAxis(Axis axis) {
|
void Motion::InitAxis(Axis axis) {
|
||||||
axes[axis].enabled = true;
|
axes[axis].enabled = true;
|
||||||
|
|
@ -23,13 +27,17 @@ void Motion::ClearStallGuardFlag(Axis axis) {
|
||||||
axes[axis].stallGuard = false;
|
axes[axis].stallGuard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Motion::PlanMove(uint16_t pulley, uint16_t idler, uint16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed) {
|
void Motion::PlanMove(int16_t pulley, int16_t idler, int16_t selector, uint16_t feedrate, uint16_t starting_speed, uint16_t ending_speed) {
|
||||||
axes[Pulley].targetPos = axes[Pulley].pos + pulley;
|
axes[Pulley].targetPos = axes[Pulley].pos + pulley;
|
||||||
axes[Idler].targetPos = axes[Idler].pos + pulley;
|
axes[Idler].targetPos = axes[Idler].pos + idler;
|
||||||
axes[Selector].targetPos = axes[Selector].pos + pulley;
|
axes[Selector].targetPos = axes[Selector].pos + selector;
|
||||||
// speeds and feedrates are not simulated yet
|
// speeds and feedrates are not simulated yet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Motion::PlanMove(Axis axis, int16_t delta, uint16_t feedrate) {
|
||||||
|
axes[axis].targetPos = axes[axis].pos + delta;
|
||||||
|
}
|
||||||
|
|
||||||
void Motion::Home(Axis axis, bool direction) {
|
void Motion::Home(Axis axis, bool direction) {
|
||||||
axes[Pulley].homed = true;
|
axes[Pulley].homed = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace motion {
|
namespace motion {
|
||||||
|
|
||||||
struct AxisSim {
|
struct AxisSim {
|
||||||
uint32_t pos;
|
int32_t pos;
|
||||||
uint32_t targetPos;
|
int32_t targetPos;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool homed;
|
bool homed;
|
||||||
bool stallGuard;
|
bool stallGuard;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ void ReinitADC(uint8_t channel, TADCData &&d, uint8_t ovsmpl) {
|
||||||
/// ADC access routines
|
/// ADC access routines
|
||||||
uint16_t ReadADC(uint8_t adc) {
|
uint16_t ReadADC(uint8_t adc) {
|
||||||
if (!oversample) {
|
if (!oversample) {
|
||||||
++rdptr[adc];
|
if (rdptr[adc] != values2Return[adc].end())
|
||||||
|
++rdptr[adc];
|
||||||
oversample = oversampleFactor;
|
oversample = oversampleFactor;
|
||||||
} else {
|
} else {
|
||||||
--oversample;
|
--oversample;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue