Skip to content

Commit

Permalink
Merge pull request #196 from clholgat/clholgat/garter_carriage
Browse files Browse the repository at this point in the history
Systemic changes to support garter carriage on the full bed
  • Loading branch information
X-sam authored Sep 8, 2024
2 parents 4ecb729 + 52cd583 commit 278cbbe
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 138 deletions.
6 changes: 6 additions & 0 deletions src/ayab/beeper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ void Beeper::endWork() {
}
}

void Beeper::error() {
if (m_enabled) {
beep(BEEP_NUM_ERROR);
}
}

/*!
* Beep handler scheduled from main loop
*/
Expand Down
4 changes: 4 additions & 0 deletions src/ayab/beeper.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ constexpr unsigned int BEEP_DELAY = 50U; // ms
constexpr uint8_t BEEP_NUM_READY = 5U;
constexpr uint8_t BEEP_NUM_FINISHEDLINE = 3U;
constexpr uint8_t BEEP_NUM_ENDWORK = 10U;
constexpr uint8_t BEEP_NUM_ERROR = 15U;

constexpr uint8_t BEEP_ON_DUTY = 0U;
constexpr uint8_t BEEP_OFF_DUTY = 20U;
Expand All @@ -49,6 +50,7 @@ class BeeperInterface {
virtual void ready() = 0;
virtual void finishedLine() = 0;
virtual void endWork() = 0;
virtual void error() = 0;
virtual void schedule() = 0;
};

Expand All @@ -72,6 +74,7 @@ class GlobalBeeper final {
static void ready();
static void finishedLine();
static void endWork();
static void error();
static void schedule();
};

Expand All @@ -86,6 +89,7 @@ class Beeper : public BeeperInterface {
void ready() final;
void finishedLine() final;
void endWork() final;
void error() final;
void schedule() final;

private:
Expand Down
98 changes: 75 additions & 23 deletions src/ayab/encoders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ void Encoders::init(Machine_t machineType) {
m_beltShift = BeltShift::Unknown;
m_carriage = Carriage_t::NoCarriage;
m_oldState = false;
m_passedLeft = false;
m_passedRight = false;
}

/*!
Expand Down Expand Up @@ -133,20 +135,13 @@ void Encoders::encA_rising() {
m_direction = digitalRead(ENC_PIN_B) != 0 ? Direction_t::Right : Direction_t::Left;

// Update carriage position
if ((Direction_t::Right == m_direction) && (m_position < END_RIGHT[static_cast<uint8_t>(m_machineType)])) {
m_position = m_position + 1;
}

// The garter carriage has a second set of magnets that are going to
// pass the sensor and will reset state incorrectly if allowed to
// continue.
if (m_carriage == Carriage_t::Garter) {
return;
}
if (Direction_t::Right == m_direction) {
m_position = m_position + (uint8_t) 1;

// If the carriage is already set, ignore the rest.
if ((m_carriage == Carriage_t::Knit) && (m_machineType == Machine_t::Kh270)) {
return;
// Reset carriage passed state when we know all magnets have cleared the turn mark.
if (m_position > ALL_MAGNETS_CLEARED_LEFT[static_cast<uint8_t>(m_machineType)]) {
m_passedLeft = false;
}
}

// In front of Left Hall Sensor?
Expand All @@ -155,6 +150,38 @@ void Encoders::encA_rising() {
(hallValue > FILTER_L_MAX[static_cast<uint8_t>(m_machineType)])) {
m_hallActive = Direction_t::Left;

// Only set the belt shift the first time a magnet passes the turn mark.
// Headed to the right.
if (!m_passedLeft && Direction_t::Right == m_direction) {
// Belt shift signal only decided in front of hall sensor
m_beltShift = digitalRead(ENC_PIN_C) != 0 ? BeltShift::Shifted : BeltShift::Regular;
m_passedLeft = true;

if (Carriage_t::Garter == m_carriage) {
// This has to be the first magnet and the belt shift needs to be swapped
// But only for the G-carriage
if (m_position < 30) {
if (BeltShift::Regular == m_beltShift) {
m_beltShift = BeltShift::Shifted;
} else {
m_beltShift = BeltShift::Regular;
}
}
}
}

// The garter carriage has a second set of magnets that are going to
// pass the sensor and will reset state incorrectly if allowed to
// continue.
if (Carriage_t::Garter == m_carriage) {
return;
}

// If the carriage is already set, ignore the rest.
if ((Carriage_t::Knit == m_carriage) && (Machine_t::Kh270 == m_machineType)) {
return;
}

Carriage detected_carriage = Carriage_t::NoCarriage;
uint8_t start_position = END_LEFT_PLUS_OFFSET[static_cast<uint8_t>(m_machineType)];

Expand All @@ -176,16 +203,25 @@ void Encoders::encA_rising() {
} else if (m_carriage != detected_carriage && m_position > start_position) {
m_carriage = Carriage_t::Garter;

// We swap the belt shift for the g-carriage because the point of work for
// the g-carraige is 13 needles behind the first magnet which puts it in a different
// belt shift.
// And we need to know the belt shift when the point of work is at needle 0.
// Conveniently, the magnet distance on the K and L carraiges puts the point of
// work within the same belt shift.
if (BeltShift::Regular == m_beltShift) {
m_beltShift = BeltShift::Shifted;
} else {
m_beltShift = BeltShift::Regular;
}

// Belt shift and start position were set when the first magnet passed
// the sensor and we assumed we were working with a standard carriage.
return;
} else {
m_carriage = detected_carriage;
}

// Belt shift signal only decided in front of hall sensor
m_beltShift = digitalRead(ENC_PIN_C) != 0 ? BeltShift::Regular : BeltShift::Shifted;

// Known position of the carriage -> overwrite position
m_position = start_position;
}
Expand All @@ -203,8 +239,13 @@ void Encoders::encA_falling() {
m_direction = digitalRead(ENC_PIN_B) ? Direction_t::Left : Direction_t::Right;

// Update carriage position
if ((Direction_t::Left == m_direction) && (m_position > END_LEFT[static_cast<uint8_t>(m_machineType)])) {
m_position = m_position - 1;
if (Direction_t::Left == m_direction) {
m_position = m_position - (uint8_t) 1;

// Reset carriage passed state when we know all magnets have cleared the turn mark.
if (m_position < ALL_MAGNETS_CLEARED_RIGHT[static_cast<uint8_t>(m_machineType)]) {
m_passedRight = false;
}
}

// In front of Right Hall Sensor?
Expand All @@ -219,15 +260,26 @@ void Encoders::encA_falling() {
if (hallValueSmall || hallValue > FILTER_R_MAX[static_cast<uint8_t>(m_machineType)]) {
m_hallActive = Direction_t::Right;

// The garter carriage has a second set of magnets that are going to
// Only set the belt shift when the first magnet passes the turn mark.
// Headed to the left.
if (!m_passedRight && Direction_t::Left == m_direction) {
// Belt shift signal only decided in front of hall sensor
m_beltShift = digitalRead(ENC_PIN_C) != 0 ? BeltShift::Regular : BeltShift::Shifted;
m_passedRight = true;

// Shift doens't need to be swapped for the g-carriage in this direction.
}

// The garter carriage has extra magnets that are going to
// pass the sensor and will reset state incorrectly if allowed to
// continue.
if (hallValueSmall && (m_carriage != Carriage_t::Garter)) {
m_carriage = Carriage_t::Knit;
if (m_carriage == Carriage_t::Garter) {
return;
}

// Belt shift signal only decided in front of hall sensor
m_beltShift = digitalRead(ENC_PIN_C) != 0 ? BeltShift::Shifted : BeltShift::Regular;
if (hallValueSmall) {
m_carriage = Carriage_t::Knit;
}

// Known position of the carriage -> overwrite position
m_position = END_RIGHT_MINUS_OFFSET[static_cast<uint8_t>(m_machineType)];
Expand Down
13 changes: 9 additions & 4 deletions src/ayab/encoders.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ constexpr uint8_t END_OFFSET[NUM_MACHINES] = {28U, 28U, 5U};
constexpr uint8_t END_LEFT_PLUS_OFFSET[NUM_MACHINES] = {28U, 28U, 5U};
constexpr uint8_t END_RIGHT_MINUS_OFFSET[NUM_MACHINES] = {227U, 227U, 135U};

constexpr uint8_t ALL_MAGNETS_CLEARED_LEFT[NUM_MACHINES] = {56U, 56U, 10U};
constexpr uint8_t ALL_MAGNETS_CLEARED_RIGHT[NUM_MACHINES] = {199U, 199U, 130U};

// The garter slop is needed to determine whether or not we have a garter carriage.
// If we didn't have it, we'd decide which carriage we had when the first magnet passed the sensor.
// For the garter carriage we need to see both magnets.
Expand All @@ -83,14 +86,14 @@ constexpr uint8_t START_OFFSET[NUM_MACHINES][NUM_DIRECTIONS][NUM_CARRIAGES] = {
// KH910
{
// K, L, G
{40U, 40U, 32U}, // Left
{16U, 16U, 56U} // Right
{42U, 32U, 32U}, // Left
{16U, 32U, 50U} // Right
},
// KH930
{
// K, L, G
{40U, 40U, 32U}, // Left
{16U, 16U, 56U} // Right
{42U, 32U, 32U}, // Left
{16U, 32U, 50U} // Right
},
// KH270
{
Expand Down Expand Up @@ -181,6 +184,8 @@ class Encoders : public EncodersInterface {
volatile Direction_t m_hallActive;
volatile uint8_t m_position;
volatile bool m_oldState;
volatile bool m_passedLeft;
volatile bool m_passedRight;

void encA_rising();
void encA_falling();
Expand Down
4 changes: 4 additions & 0 deletions src/ayab/global_beeper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ void GlobalBeeper::endWork() {
m_instance->endWork();
}

void GlobalBeeper::error() {
m_instance->error();
}

void GlobalBeeper::schedule() {
m_instance->schedule();
}
52 changes: 16 additions & 36 deletions src/ayab/knitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ void Knitter::knit() {
}

if (!calculatePixelAndSolenoid()) {
// no valid/useful position calculated
// This will only happen if there's an error
GlobalBeeper::error();
return;
}

Expand Down Expand Up @@ -386,7 +387,8 @@ void Knitter::reqLine(uint8_t lineNumber) {
*/
bool Knitter::calculatePixelAndSolenoid() {
uint8_t startOffset = 0;
uint8_t laceOffset = 0;

bool beltShift = BeltShift_t::Shifted == m_beltShift;

switch (m_direction) {
// calculate the solenoid and pixel to be set
Expand All @@ -395,51 +397,29 @@ bool Knitter::calculatePixelAndSolenoid() {
case Direction_t::Right:
startOffset = getStartOffset(Direction_t::Left);

// We have to start setting pixels earlier when the lace carriage is selected because we shift
// the lace pixel selection up HALF_SOLENOIDS_NUM in this direction. Doesn't matter going back
// the other way.
// The Lace carriage is special
// See page 7 of the 930 service manual https://mkmanuals.com/downloadable/download/sample/sample_id/27/
if (Carriage_t::Lace == m_carriage) {
laceOffset = HALF_SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
beltShift = !beltShift;
}

if (m_position >= startOffset - laceOffset) {
m_pixelToSet = m_position - startOffset;

if ((BeltShift::Regular == m_beltShift) || (m_machineType == Machine_t::Kh270)) {
m_solenoidToSet = m_position % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
} else if (BeltShift::Shifted == m_beltShift) {
m_solenoidToSet = (m_position - HALF_SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)]) % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
}
if (Carriage_t::Lace == m_carriage) {
m_pixelToSet = m_pixelToSet + HALF_SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
}
} else {
return false;
}
break;

case Direction_t::Left:
startOffset = getStartOffset(Direction_t::Right);
if (m_position <= (END_RIGHT[static_cast<uint8_t>(m_machineType)] - startOffset)) {
m_pixelToSet = m_position - startOffset;

if ((BeltShift::Regular == m_beltShift) || (m_machineType == Machine_t::Kh270)) {
m_solenoidToSet = (m_position + HALF_SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)]) % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
} else if (BeltShift::Shifted == m_beltShift) {
m_solenoidToSet = m_position % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
}
if (Carriage_t::Lace == m_carriage) {
m_pixelToSet = m_pixelToSet - SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
}
} else {
return false;
}
break;

break;
default:
return false;
}

m_pixelToSet = m_position - startOffset;

if (!beltShift) {
m_solenoidToSet = m_pixelToSet % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
} else {
m_solenoidToSet = (m_pixelToSet + HALF_SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)]) % SOLENOIDS_NUM[static_cast<uint8_t>(m_machineType)];
}

// The 270 has 12 solenoids but they get shifted over 3 bits
if (m_machineType == Machine_t::Kh270) {
m_solenoidToSet = m_solenoidToSet + 3;
Expand Down
5 changes: 5 additions & 0 deletions test/mocks/beeper_mock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ void Beeper::finishedLine() {
gBeeperMock->finishedLine();
}

void Beeper::error() {
assert(gBeeperMock != nullptr);
gBeeperMock->error();
}

void Beeper::endWork() {
assert(gBeeperMock != nullptr);
gBeeperMock->endWork();
Expand Down
1 change: 1 addition & 0 deletions test/mocks/beeper_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class BeeperMock : public BeeperInterface {
MOCK_METHOD0(getState, BeepState());
MOCK_METHOD0(ready, void());
MOCK_METHOD0(finishedLine, void());
MOCK_METHOD0(error, void());
MOCK_METHOD0(endWork, void());
MOCK_METHOD0(schedule, void());
};
Expand Down
Loading

0 comments on commit 278cbbe

Please # to comment.