From 1c469a52f3e271642c9dcb03ffbd01bb683ebc52 Mon Sep 17 00:00:00 2001 From: Jonathan Perret Date: Sun, 15 Dec 2024 21:05:02 +0100 Subject: [PATCH] Encoders: only look at leftmost edge of left sensor signal The code in encA_rising used to reset the carriage position to "zero" for every needle where the sensor was triggered. This caused the zero position to be taken as the rightmost position where a magnet was detected (a magnet is usually detected for two to three needle widths). In turn this caused solenoids to sometimes be activated too late to correctly select needles. By checking for the signal going from "no magnet detected" to "any magnet detected", the "zero" position will be set only at the leftmost edge of the magnet detection area. This should shift everything left by one or two needles, leaving more time for the solenoids to be activated. --- src/ayab/encoders.cpp | 31 +++++++++++------- src/ayab/encoders.h | 2 ++ test/test_encoders.cpp | 71 +++++++++++++++++++++++++++++------------- 3 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/ayab/encoders.cpp b/src/ayab/encoders.cpp index c5c63043..5b5ae4aa 100644 --- a/src/ayab/encoders.cpp +++ b/src/ayab/encoders.cpp @@ -74,6 +74,7 @@ void Encoders::init(Machine_t machineType) { m_hallActive = Direction_t::NoDirection; m_beltShift = BeltShift::Unknown; m_carriage = Carriage_t::NoCarriage; + m_previousDetectedCarriageLeft = detectCarriageLeft(); m_oldState = false; m_passedLeft = false; m_passedRight = false; @@ -123,6 +124,16 @@ Machine_t Encoders::getMachineType() { // Private Methods +Carriage_t Encoders::detectCarriageLeft() { + uint16_t hallValue = analogRead(EOL_PIN_L); + if (hallValue > FILTER_L_MAX[static_cast(m_machineType)]) { + return Carriage_t::Knit; + } else if (hallValue < FILTER_L_MIN[static_cast(m_machineType)]){ + return Carriage_t::Lace; + } + return Carriage_t::NoCarriage; +} + /*! * \brief Interrupt service subroutine. * @@ -144,10 +155,15 @@ void Encoders::encA_rising() { } } - // In front of Left Hall Sensor and headed to the right? - uint16_t hallValue = analogRead(EOL_PIN_L); - if (Direction_t::Right == m_direction && ((hallValue < FILTER_L_MIN[static_cast(m_machineType)]) || - (hallValue > FILTER_L_MAX[static_cast(m_machineType)]))) { + // Scan for carriage in front of left Hall sensor + Carriage_t detected_carriage = detectCarriageLeft(); + Carriage_t previous_detected_carriage = m_previousDetectedCarriageLeft; + m_previousDetectedCarriageLeft = detected_carriage; + + // New carriage detected and headed to the right? + if (Direction_t::Right == m_direction && + detected_carriage != Carriage_t::NoCarriage && + detected_carriage != previous_detected_carriage) { m_hallActive = Direction_t::Left; // Only set the belt shift the first time a magnet passes the turn mark. @@ -182,15 +198,8 @@ void Encoders::encA_rising() { return; } - Carriage detected_carriage = Carriage_t::NoCarriage; uint8_t start_position = END_LEFT_PLUS_OFFSET[static_cast(m_machineType)]; - if (hallValue >= FILTER_L_MIN[static_cast(m_machineType)]) { - detected_carriage = Carriage_t::Knit; - } else { - detected_carriage = Carriage_t::Lace; - } - if (m_machineType == Machine_t::Kh270) { m_carriage = Carriage_t::Knit; diff --git a/src/ayab/encoders.h b/src/ayab/encoders.h index 28c7256d..8295170f 100644 --- a/src/ayab/encoders.h +++ b/src/ayab/encoders.h @@ -180,6 +180,7 @@ class Encoders : public EncodersInterface { volatile BeltShift_t m_beltShift; volatile Carriage_t m_carriage; + volatile Carriage_t m_previousDetectedCarriageLeft; volatile Direction_t m_direction; volatile Direction_t m_hallActive; volatile uint8_t m_position; @@ -187,6 +188,7 @@ class Encoders : public EncodersInterface { volatile bool m_passedLeft; volatile bool m_passedRight; + Carriage_t detectCarriageLeft(); void encA_rising(); void encA_falling(); }; diff --git a/test/test_encoders.cpp b/test/test_encoders.cpp index ff84f17a..47fa8e7d 100644 --- a/test/test_encoders.cpp +++ b/test/test_encoders.cpp @@ -30,10 +30,18 @@ using ::testing::Return; extern Encoders *encoders; +const int MID_SENSOR_VALUE = 400; + class EncodersTest : public ::testing::Test { protected: void SetUp() override { arduinoMock = arduinoMockInstance(); + + // No triggered sensor at init time + EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)) + .WillOnce(Return(MID_SENSOR_VALUE)) + .RetiresOnSaturation(); + encoders->init(Machine_t::Kh910); } @@ -68,36 +76,52 @@ TEST_F(EncodersTest, test_encA_rising_not_in_front) { TEST_F(EncodersTest, test_encA_rising_in_front_notKH270) { ASSERT_FALSE(encoders->getMachineType() == Machine_t::Kh270); ASSERT_EQ(encoders->getCarriage(), Carriage_t::NoCarriage); - // We should not enter the falling function - EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_R)).Times(0); - // Create a rising edge - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)).WillOnce(Return(false)); - // We have not entered the rising function yet - EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)).Times(0); - - encoders->encA_interrupt(); - - // Create a rising edge - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)).WillOnce(Return(true)); - // Enter rising function, direction is right - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_B)).WillOnce(Return(true)); + // Not in front of Right Hall Sensor + EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_R)) + .WillRepeatedly(Return(MID_SENSOR_VALUE)); // In front of Left Hall Sensor EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)) - .WillOnce(Return(FILTER_L_MIN[static_cast(encoders->getMachineType())] - 1)); - // BeltShift is regular - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_C)).WillOnce(Return(true)); - + .WillRepeatedly(Return(FILTER_L_MIN[static_cast(encoders->getMachineType())] - 1)); + // BeltShift is shifted + EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_C)).WillRepeatedly(Return(HIGH)); + // Create two rising edges (the initial state of A is assumed to be low) + EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)) + .WillOnce(Return(HIGH)) + .WillOnce(Return(LOW)) + .WillOnce(Return(HIGH)); + // Always moving to the right: A == B + EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_B)) + .WillOnce(Return(HIGH)) + .WillOnce(Return(LOW)) + .WillOnce(Return(HIGH)); + + // Process rising edge encoders->encA_interrupt(); + uint8_t startPosition = END_OFFSET[static_cast(encoders->getMachineType())]; + ASSERT_EQ(encoders->getDirection(), Direction_t::Right); ASSERT_EQ(encoders->getHallActive(), Direction_t::Left); - ASSERT_EQ(encoders->getPosition(), END_OFFSET[static_cast(encoders->getMachineType())]); ASSERT_EQ(encoders->getCarriage(), Carriage_t::Lace); ASSERT_EQ(encoders->getBeltShift(), BeltShift::Shifted); + ASSERT_EQ(encoders->getPosition(), startPosition); + + // Process falling edge + encoders->encA_interrupt(); + + // Process rising edge + encoders->encA_interrupt(); + + // Should have moved and not reset position + ASSERT_EQ(encoders->getPosition(), 1 + startPosition); } TEST_F(EncodersTest, test_encA_rising_in_front_KH270) { + EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)) + .WillOnce(Return(MID_SENSOR_VALUE)) + .RetiresOnSaturation(); encoders->init(Machine_t::Kh270); + ASSERT_TRUE(encoders->getMachineType() == Machine_t::Kh270); // We should not enter the falling function EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_R)).Times(0); @@ -187,20 +211,20 @@ TEST_F(EncodersTest, test_encA_falling_not_in_front) { TEST_F(EncodersTest, test_encA_falling_in_front) { // Create a falling edge EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)) - .WillOnce(Return(true)) - .WillOnce(Return(true)); + .WillOnce(Return(HIGH)) + .WillOnce(Return(HIGH)); // We have not entered the falling function yet EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_R)).Times(0); // Enter rising function, direction is left - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_B)).WillOnce(Return(false)).WillOnce(Return(false)); + EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_B)).WillOnce(Return(LOW)).WillOnce(Return(LOW)); // In front of Left Hall Sensor EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)) .WillOnce(Return(FILTER_L_MIN[static_cast(encoders->getMachineType())])); encoders->encA_interrupt(); encoders->encA_interrupt(); - EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)).WillOnce(Return(false)); + EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_A)).WillOnce(Return(LOW)); EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_R)) .WillOnce(Return(FILTER_R_MAX[static_cast(encoders->getMachineType())] + 1)); @@ -263,6 +287,9 @@ TEST_F(EncodersTest, test_getMachineType) { } TEST_F(EncodersTest, test_init) { + EXPECT_CALL(*arduinoMock, analogRead(EOL_PIN_L)) + .WillOnce(Return(MID_SENSOR_VALUE)) + .RetiresOnSaturation(); encoders->init(Machine_t::Kh270); Machine_t m = encoders->getMachineType(); ASSERT_EQ(m, Machine_t::Kh270);