Files
feeder_mk2/code/firmware/src/IndexFeeder.cpp

177 lines
4.3 KiB
C++

#include <Arduino.h>
#include "IndexFeeder.h"
#define TENTH_MM_PER_PIP 40
#define TIMEOUT_PER_PIP
#define TICKS_PER_TENTH_MM 11.3
#define TENSION_TIMEOUT 400
//pid settings and gains
#define OUTPUT_MIN 0
#define OUTPUT_MAX 255
// Unit Tests Fail Because This Isn't Defined In ArduinoFake for some reason
#ifndef INPUT_ANALOG
#define INPUT_ANALOG 0x04
#endif
IndexFeeder::IndexFeeder(uint8_t drive1_pin, uint8_t drive2_pin, uint8_t peel1_pin, uint8_t peel2_pin, RotaryEncoder* encoder) :
_drive1_pin(drive1_pin),
_drive2_pin(drive2_pin),
_peel1_pin(peel1_pin),
_peel2_pin(peel2_pin),
_encoder(encoder) {
init();
}
bool IndexFeeder::init() {
pinMode(_drive1_pin, OUTPUT);
pinMode(_drive2_pin, OUTPUT);
pinMode(_peel1_pin, OUTPUT);
pinMode(_peel2_pin, OUTPUT);
return true;
}
Feeder::FeedResult IndexFeeder::feedDistance(uint8_t tenths_mm, bool forward) {
int test = abs(tenths_mm) % TENTH_MM_PER_PIP;
// if (abs(tenths_mm) % TENTH_MM_PER_PIP != 0) {
// // The Index Feeder has only been tested and calibrated for moves of 4mm (One Pip) so far.
// // If any other value is supplied, indicate it is invalid.
// return Feeder::FeedResult::INVALID_LENGTH;
// }
bool success = (forward) ? moveForward(tenths_mm) : moveBackward(tenths_mm);
if (!success) {
return FeedResult::MOTOR_FAULT;
}
return Feeder::FeedResult::SUCCESS;
}
//returns true if we reached position within timeout, false if we didn't
bool IndexFeeder::moveInternal(uint32_t timeout, bool forward, uint8_t tenths_mm) {
signed long start_pos, goal_pos, ticks_to_move;
//move based on encoder value
//all this does is move the tape a number of ticks, and that's it!
ticks_to_move = tenths_mm * TICKS_PER_TENTH_MM;
start_pos = _encoder->getPosition();
if (forward == true) {
ticks_to_move = ticks_to_move * -1;
}
goal_pos = start_pos + ticks_to_move;
unsigned long start_time = millis();
bool ret = false;
float Kp=200, Ki=5, Kd=0, Hz=60;
int output_bits = 8;
bool output_signed = true;
FastPID pid(Kp, Ki, Kd, Hz, output_bits, output_signed);
pid.setOutputRange(-255, 255);
while(millis() < start_time + timeout){
signed long current_pos = _encoder->getPosition();
// PID implementation
signed long output = pid.step(goal_pos, current_pos);
// Stop early if we've hit steady state
if(fabs(goal_pos - current_pos) < 3){ // if we're at setpoint, set return value to true and break
ret = true;
break;
}
else { //if not at setpoint yet
if(output > 0){
analogWrite(_drive1_pin, 0);
analogWrite(_drive2_pin, output*2);
}
else {
output = abs(output);
analogWrite(_drive1_pin, output*2);
analogWrite(_drive2_pin, 0);
}
}
}
// be sure to turn off motors
analogWrite(_drive1_pin, 0);
analogWrite(_drive2_pin, 0);
return ret;
}
bool IndexFeeder::tension(uint32_t timeout) {
unsigned long start_millis, current_millis;
//tension film
digitalWrite(PA8, LOW);
analogWrite(_peel1_pin, 255);
analogWrite(_peel2_pin, 0);
delay(500);
analogWrite(_peel1_pin, 0);
analogWrite(_peel2_pin, 0);
digitalWrite(PA8, HIGH);
return true;
}
bool IndexFeeder::moveForward(uint8_t tenths_mm) {
// First, ensure everything is stopped
stop();
//peel film
tension(TENSION_TIMEOUT);
analogWrite(_peel1_pin, 255);
analogWrite(_peel2_pin, 0);
//move tape
moveInternal(5000, true, tenths_mm);
analogWrite(_peel1_pin, 0);
analogWrite(_peel2_pin, 0);
// move film
//return tension(TENSION_TIMEOUT);
return true;
}
bool IndexFeeder::moveBackward(uint8_t tenths_mm) {
// First, ensure everything is stopped
stop();
// Next, unspool some film to give the tape slack. imprecise amount because we retention later
// move tape backward
moveInternal(5000, false, tenths_mm);
stop();
//tension film again
return tension(TENSION_TIMEOUT);
}
void IndexFeeder::stop() {
// Stop Everything
analogWrite(_drive1_pin, 0);
analogWrite(_drive2_pin, 0);
analogWrite(_peel1_pin, 0);
analogWrite(_peel2_pin, 0);
}