Skip to content

Commit

Permalink
Encoders: only look at leftmost edge of left sensor signal
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jonathanperret committed Dec 15, 2024
1 parent 3e32811 commit 1b51c24
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 33 deletions.
31 changes: 20 additions & 11 deletions src/ayab/encoders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<uint8_t>(m_machineType)]) {
return Carriage_t::Knit;
} else if (hallValue < FILTER_L_MIN[static_cast<uint8_t>(m_machineType)]){
return Carriage_t::Lace;
}
return Carriage_t::NoCarriage;
}

/*!
* \brief Interrupt service subroutine.
*
Expand All @@ -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<uint8_t>(m_machineType)]) ||
(hallValue > FILTER_L_MAX[static_cast<uint8_t>(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.
Expand Down Expand Up @@ -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<uint8_t>(m_machineType)];

if (hallValue >= FILTER_L_MIN[static_cast<uint8_t>(m_machineType)]) {
detected_carriage = Carriage_t::Knit;
} else {
detected_carriage = Carriage_t::Lace;
}

if (m_machineType == Machine_t::Kh270) {
m_carriage = Carriage_t::Knit;

Expand Down
2 changes: 2 additions & 0 deletions src/ayab/encoders.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,15 @@ 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;
volatile bool m_oldState;
volatile bool m_passedLeft;
volatile bool m_passedRight;

Carriage_t detectCarriageLeft();
void encA_rising();
void encA_falling();
};
Expand Down
71 changes: 49 additions & 22 deletions test/test_encoders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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<int8_t>(encoders->getMachineType())] - 1));
// BeltShift is regular
EXPECT_CALL(*arduinoMock, digitalRead(ENC_PIN_C)).WillOnce(Return(true));

.WillRepeatedly(Return(FILTER_L_MIN[static_cast<int8_t>(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<int8_t>(encoders->getMachineType())];

ASSERT_EQ(encoders->getDirection(), Direction_t::Right);
ASSERT_EQ(encoders->getHallActive(), Direction_t::Left);
ASSERT_EQ(encoders->getPosition(), END_OFFSET[static_cast<int8_t>(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);
Expand Down Expand Up @@ -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<int8_t>(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<int8_t>(encoders->getMachineType())] + 1));

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1b51c24

Please sign in to comment.