diff --git a/test/mocks/knitting_machine.cpp b/test/mocks/knitting_machine.cpp index b35944ff..40c3d10b 100644 --- a/test/mocks/knitting_machine.cpp +++ b/test/mocks/knitting_machine.cpp @@ -5,13 +5,15 @@ #include "knitting_machine.h" const int STEPS_PER_NEEDLE = 4; +const int BELT_PHASE_OFFSET = 9; +const float MAGNET_SENSOR_RANGE = 0.75; // in needle widths const KnittingMachine::qneedle_t KnittingMachine::LEFT_POSITION_SENSOR_POSITION = - KnittingMachine::qneedle_t::fromNeedle(0); + KnittingMachine::qneedle_t::fromNeedle(-0.5); const KnittingMachine::qneedle_t KnittingMachine::RIGHT_POSITION_SENSOR_POSITION = - KnittingMachine::qneedle_t::fromNeedle(199); + KnittingMachine::qneedle_t::fromNeedle(200); bool KnittingMachine::getEncoderOutput1() const { return (m_beltPosition + 1) % STEPS_PER_NEEDLE >= 2; @@ -25,7 +27,7 @@ bool KnittingMachine::getBeltPhase() const { if (!m_hasBeltShift) { return false; } - return m_beltPosition >= (beltPeriod() / 2); + return ((m_beltPosition + beltPeriod() + BELT_PHASE_OFFSET) % beltPeriod()) >= (beltPeriod() / 2); } void KnittingMachine::moveBeltRight() { @@ -36,13 +38,12 @@ void KnittingMachine::moveBeltLeft() { m_beltPosition = (m_beltPosition + (beltPeriod() - 1)) % beltPeriod(); } -float KnittingMachine::getLeftPositionSensorVoltage() { - int carriageOffset = - (LEFT_POSITION_SENSOR_POSITION - m_carriagePosition).closestNeedle(); - for (std::pair magnet : m_carriageMagnets) { - // TODO: simulate the fact that magnets trigger sensors for - // 2-3 needle widths, not just right in front. - if (magnet.first == carriageOffset) { + +float KnittingMachine::getPositionSensorVoltage(qneedle_t sensorNeedlePos) const { + float sensorPosition = sensorNeedlePos.asNeedle(); + for (std::pair magnet : m_carriageMagnets) { + float magnetPosition = m_carriagePosition.asNeedle() + magnet.first; + if (std::abs(sensorPosition - magnetPosition) <= MAGNET_SENSOR_RANGE) { return magnet.second ? POSITION_SENSOR_HIGH_VOLTAGE : POSITION_SENSOR_LOW_VOLTAGE; } @@ -50,18 +51,12 @@ float KnittingMachine::getLeftPositionSensorVoltage() { return POSITION_SENSOR_MID_VOLTAGE; } +float KnittingMachine::getLeftPositionSensorVoltage() { + return getPositionSensorVoltage(LEFT_POSITION_SENSOR_POSITION); +} + float KnittingMachine::getRightPositionSensorVoltage() { - int carriageOffset = - (RIGHT_POSITION_SENSOR_POSITION - m_carriagePosition).closestNeedle(); - for (std::pair magnet : m_carriageMagnets) { - // TODO: simulate the fact that magnets trigger sensors for - // 2-3 needle widths, not just right in front. - if (magnet.first == carriageOffset) { - return magnet.second ? POSITION_SENSOR_HIGH_VOLTAGE - : POSITION_SENSOR_LOW_VOLTAGE; - } - } - return POSITION_SENSOR_MID_VOLTAGE; + return getPositionSensorVoltage(RIGHT_POSITION_SENSOR_POSITION); } float KnittingMachine::getRightPositionSensorKSignal() { @@ -70,10 +65,17 @@ float KnittingMachine::getRightPositionSensorKSignal() { : POSITION_SENSOR_MID_VOLTAGE; } -void KnittingMachine::addCarriageMagnet(int offsetFromCenter, bool polarity) { +void KnittingMachine::addCarriageMagnet(float offsetFromCenter, bool polarity) { m_carriageMagnets.push_back(std::make_pair(offsetFromCenter, polarity)); } +void KnittingMachine::addGCarriageMagnets() { + addCarriageMagnet(12.25, false); + addCarriageMagnet(10.5, true); + addCarriageMagnet(-10.5, true); + addCarriageMagnet(-12.25, false); +} + void KnittingMachine::putCarriageCenterInFrontOfNeedle(int position) { m_carriagePosition = qneedle_t::fromNeedle(position); // convert to 1/4 of needles @@ -84,6 +86,10 @@ int KnittingMachine::getCarriageCenterNeedle() { } bool KnittingMachine::carriageEngagesBelt() const { + // TODO disengage carriage when it moves outside the bed + // TODO simulate carriage belt hooks (currently simulates + // a single hook at carriage center) + // TODO simulate belt slack int period = STEPS_PER_NEEDLE * m_solenoidCount; if (m_hasBeltShift) { period /= 2; diff --git a/test/mocks/knitting_machine.h b/test/mocks/knitting_machine.h index cf869f89..6f1bf3fe 100644 --- a/test/mocks/knitting_machine.h +++ b/test/mocks/knitting_machine.h @@ -2,6 +2,7 @@ #define KNITTINGMACHINE_H_ #include +#include #include #include @@ -68,7 +69,12 @@ class KnittingMachine { * (positive = right) * \param polarity the magnet's polarity — (true = North, like K carriage) */ - void addCarriageMagnet(int offsetFromCenter, bool polarity); + void addCarriageMagnet(float offsetFromCenter, bool polarity); + + /** + * Helper to add all G-carriage magnets (as measured on a KG-89) + */ + void addGCarriageMagnets(); /** * Set the carriage's position on the bed. This does not move the belt, @@ -134,14 +140,17 @@ class KnittingMachine { --value; return *this; } + float asNeedle() const { + return value / 4.0; + } int closestNeedle() const { - return std::round(value / 4.0); + return std::round(asNeedle()); } int leftNeedle() const { - return std::floor(value / 4.0); + return std::floor(asNeedle()); } - static qneedle_t fromNeedle(int needle) { - return {needle * 4}; + static qneedle_t fromNeedle(float needle) { + return {(int)std::round(needle * 4)}; } }; @@ -165,6 +174,11 @@ class KnittingMachine { */ bool carriageEngagesBelt() const; + /** + * Get the voltage at a position sensor given its position + */ + float getPositionSensorVoltage(qneedle_t sensorNeedlePosition) const; + /** * How many solenoids the machine has */ @@ -184,7 +198,7 @@ class KnittingMachine { * A belt position of 0 represents a belt position where an * elongated hole is in front of the left position sensor. */ - uint8_t m_beltPosition = 0; + std::uint8_t m_beltPosition = 0; /** * The carriage position in 1/4 needles. @@ -197,7 +211,7 @@ class KnittingMachine { * A list of carriage magnets, defined by their offset from the carriage * center and their polarity. \see addCarriageMagnet() */ - std::vector> m_carriageMagnets; + std::vector> m_carriageMagnets; }; #endif // KNITTINGMACHINE_H_ \ No newline at end of file diff --git a/test/test_knitting_machine.cpp b/test/test_knitting_machine.cpp index c50412f8..b7be259b 100644 --- a/test/test_knitting_machine.cpp +++ b/test/test_knitting_machine.cpp @@ -99,10 +99,7 @@ TEST(KnittingMachine, LCarriageDetectionOnTheLeft) { TEST(KnittingMachine, GCarriageDetectionOnTheLeft) { KnittingMachine km; - km.addCarriageMagnet(12, false); - km.addCarriageMagnet(11, true); - km.addCarriageMagnet(-11, true); - km.addCarriageMagnet(-12, false); + km.addGCarriageMagnets(); km.putCarriageCenterInFrontOfNeedle(-12); ASSERT_THAT(km.getLeftPositionSensorVoltage(), Lt(0.4)); @@ -113,10 +110,10 @@ TEST(KnittingMachine, GCarriageDetectionOnTheLeft) { km.putCarriageCenterInFrontOfNeedle(0); ASSERT_THAT(km.getLeftPositionSensorVoltage(), AllOf(Gt(0.4), Lt(3.4))); - km.putCarriageCenterInFrontOfNeedle(11); + km.putCarriageCenterInFrontOfNeedle(10); ASSERT_THAT(km.getLeftPositionSensorVoltage(), Gt(3.4)); - km.putCarriageCenterInFrontOfNeedle(12); + km.putCarriageCenterInFrontOfNeedle(11); ASSERT_THAT(km.getLeftPositionSensorVoltage(), Lt(0.4)); } @@ -129,7 +126,7 @@ TEST(KnittingMachine, KCarriageDetectionOnTheRight) { ASSERT_THAT(km.getRightPositionSensorVoltage(), AllOf(Gt(0.4), Lt(3.4))); ASSERT_THAT(km.getRightPositionSensorKSignal(), AllOf(Gt(1), Lt(4))); - km.putCarriageCenterInFrontOfNeedle(199); + km.putCarriageCenterInFrontOfNeedle(200); ASSERT_THAT(km.getRightPositionSensorVoltage(), Gt(3.4)); ASSERT_THAT(km.getRightPositionSensorKSignal(), Lt(0.4)); @@ -140,7 +137,6 @@ TEST(KnittingMachine, KCarriageDetectionOnTheRight) { ASSERT_THAT(km.getRightPositionSensorKSignal(), AllOf(Gt(1), Lt(4))); } - TEST(KnittingMachine, MoveCarriageIncrementally) { KnittingMachine km; @@ -179,26 +175,13 @@ TEST(KnittingMachine, BeltPhaseSignal) { for (int i = 0; i < 8 * 4; i++) { km.moveBeltLeft(); - ASSERT_TRUE(km.getBeltPhase()); - } - - km.moveBeltLeft(); - ASSERT_FALSE(km.getBeltPhase()); - - for (int i = 0; i < 8 * 4; i++) { - km.moveBeltRight(); - ASSERT_TRUE(km.getBeltPhase()); } + ASSERT_TRUE(km.getBeltPhase()); for (int i = 0; i < 8 * 4; i++) { km.moveBeltRight(); - ASSERT_FALSE(km.getBeltPhase()); } - - km.moveBeltRight(); - ASSERT_TRUE(km.getBeltPhase()); - - km.putCarriageCenterInFrontOfNeedle(0); + ASSERT_FALSE(km.getBeltPhase()); } TEST(KnittingMachine, CarriageMovesBeltOnlyWhenInSync) { @@ -207,7 +190,7 @@ TEST(KnittingMachine, CarriageMovesBeltOnlyWhenInSync) { ASSERT_FALSE(km.getBeltPhase()); // Setting the carriage in a position where its belt hooks don't engage belt - // holes. + // holes (because they are offset). km.putCarriageCenterInFrontOfNeedle(1); // So when it moves to the left, the belt doesn't move, its phase doesn't @@ -218,7 +201,43 @@ TEST(KnittingMachine, CarriageMovesBeltOnlyWhenInSync) { // Now that the carriage is at a belt position divisible by 8, it's engaged // and the belt moves. - while (km.moveCarriageCenterTowardsNeedle(-1)) { - ASSERT_TRUE(km.getBeltPhase()); + while (km.moveCarriageCenterTowardsNeedle(-4)) { + } + ASSERT_TRUE(km.getBeltPhase()); +} + +/** + * Helper to print the value of all signals while moving a carriage + * across the bed. + * The output can be extracted and compared with a similar scan + * recorded on an actual machine. + * Sample `ctest` invocation to extract data: + * + * ctest --test-dir test/build -V -R KCarriageScanBed|grep SCAN=|cut -d= -f2 + */ +void doBedScan(KnittingMachine &km) { + float centerNeedle = -32; + km.putCarriageCenterInFrontOfNeedle(centerNeedle); + + while (km.moveCarriageCenterTowardsNeedle(231)) { + centerNeedle += 1.0 / 4; + printf("SCAN=%g\t%g\t%g\t%g\t%d\n", centerNeedle, + km.getLeftPositionSensorVoltage(), + km.getRightPositionSensorVoltage(), + km.getRightPositionSensorKSignal(), km.getBeltPhase() ? 5 : 0); } +} + +TEST(KnittingMachine, GCarriageScanBed) { + KnittingMachine km; + + km.addGCarriageMagnets(); + doBedScan(km); +} + +TEST(KnittingMachine, KCarriageScanBed) { + KnittingMachine km; + + km.addCarriageMagnet(0, true); + doBedScan(km); } \ No newline at end of file