Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
feederController.cpp
- Committer:
- Issus
- Date:
- 2017-02-04
- Revision:
- 1:4d3738338cf1
- Parent:
- 0:617334d8e3bb
File content as of revision 1:4d3738338cf1:
#include "mbed.h"
#include "USBSerial.h"
#include "HBridge.h"
#include "feeder.h"
#include "IAP_LPC11U.h"
extern "C" void mbed_mac_address(char *);
/************
TODO LIST:
*************
* printf needs to be replace with a function that putc instead for non-formatted strings
* Convert lanes to a class so they there isn't duplicate code
* Store lane distance in EEPROM
* Store retrievable aribitrary text for the lane in EEPROM (loaded part, openpnp part feeder name, whatever)
*************/
// SETTINGS
#define TAPE_MAX_PULL_TIME 3 // seconds
#define TAPE_MIN_PULL_TIME 1 // seconds
#define FEED_FWD_ENC_PULSE 2 // it's actually this value + 1
// encoder pulses: >(lane0FeedDistance * FEED_FWD_ENC_PULSE)
// 3 for 1 position, 5 for 2 positions
/*****************************************************************************
**** GLOBALS
*****************************************************************************/
// SERIAL COMMAND INPUT
enum command_t { READYFORCOMMAND, FEED, PICK, CLOSE, CONFIG };
command_t pcCommand = READYFORCOMMAND;
int pcCommandPos = 0;
enum config_t { NONE, LANE };
config_t pcConfig = NONE;
enum lane_t { UNSELECTED, ZERO, ONE };
lane_t selectedLane = UNSELECTED;
// LANE STATES
enum laneState_t { IDLE, PICKING, FEEDING, REVERSING };
laneState_t lane0State = IDLE;
laneState_t lane1State = IDLE;
// LANE EDGE STATES
int lane0LastEdge = 0;
int lane1LastEdge = 0;
// LANE EDGE COUNTERS
int lane0FeedEdge = 0;
int lane1FeedEdge = 0;
// NUMBER OF POSITIONS TO FEED THROUGH
int lane0FeedDistance = 1; // 1 = 2mm, 2 = 4mm
int lane1FeedDistance = 1;
// FEEDER END BUTTON STATES
int button0LastState = 0;
int button1LastState = 0;
// FEED STATE
bool lane0Feed = 0;
bool lane1Feed = 0;
// PICKUP STATE
bool tape0Takeup = 0;
bool tape1Takeup = 0;
// FEED STOPPER
Timeout lane0Feedout;
Timeout lane1Feedout;
// TAPE PICKUP STOPPER
Timer tape0PullTime;
Timer tape1PullTime;
/*****************************************************************************
**** HARDWARE
*****************************************************************************/
// SOLENOIDS (TAPE COVER) - keep above usb to turn off quickly
DigitalOut SOLENOID_0(PIN_SOLCTL_0, 0);
DigitalOut SOLENOID_1(PIN_SOLCTL_1, 0);
// USB VCOM UART for MBED Serial Port Driver
USBSerial pc(0x1f00, 0x2012, 0x0001, false);
// RS485
//Serial control(PIN_UART_TXD, PIN_UART_RXD, 115200);
DigitalOut RS485_DIR(PIN_RS485_DIR);
// MOTOR DRIVERS - FEED
HBridge feedMotor1(PIN_H1_IN1,PIN_H1_IN2);
HBridge feedMotor0(PIN_H1_IN3,PIN_H1_IN4);
// MOTOR DRIVERS - TAPE
HBridge tapeMotor0(PIN_H2_IN2, PIN_H2_IN1);
HBridge tapeMotor1(PIN_H2_IN4, PIN_H2_IN3);
// GATES
InterruptIn LN0_FEEDGATE(PIN_GATE_0);
InterruptIn LN1_FEEDGATE(PIN_GATE_1);
InterruptIn LN0_TAPEGATE(PIN_GATE_2);
InterruptIn LN1_TAPEGATE(PIN_GATE_3);
// FEEDER END BUTTONS
InterruptIn BUTTON_GREEN_0(PIN_BTN_GREEN_0);
InterruptIn BUTTON_GREEN_1(PIN_BTN_GREEN_1);
InterruptIn BUTTON_YELLOW_0(PIN_LED_YELLOW_0);
InterruptIn BUTTON_YELLOW_1(PIN_LED_YELLOW_1);
InterruptIn BUTTON_BOARD_FEED(PIN_BOARD_FEED);
// FEEDER END LEDS
DigitalOut LED_0(PIN_BTN_LED_0);
DigitalOut LED_1(PIN_BTN_LED_1);
// DIGITAL CONTROL INPUT
InterruptIn LANEIN_0(PIN_LANECTL_0);
InterruptIn LANEIN_1(PIN_LANECTL_1);
/*****************************************************************************
**** TAPE SLACK PICKUP
*****************************************************************************/
void stopTapeL0()
{
tape0PullTime.stop();
tape0Takeup = 0;
tapeMotor0.Coast();
}
void stopTapeL1()
{
tape1PullTime.stop();
tape1Takeup = 0;
tapeMotor1.Coast();
}
/*****************************************************************************
**** BUTTON INTERRUPTS
*****************************************************************************/
void button_yellow_0_int()
{
pc.printf("Yellow Button 0 Press\r\n");
}
void button_yellow_1_int()
{
pc.printf("Yellow Button 1 Press\r\n");
}
/*****************************************************************************
**** LANE 0 FEED CONTROL
*****************************************************************************/
void setLane0Picking()
{
lane0State = PICKING;
//todo: PwmOut
SOLENOID_0 = 1;
}
void setLane0Feeding()
{
lane0State = FEEDING;
lane0FeedEdge = 0;
lane0LastEdge = LN0_FEEDGATE;
// solenoid release
SOLENOID_0 = 0;
lane0Feed = 1;
// motor on
feedMotor0.Forward();
}
void setLane0Reversing()
{
feedMotor0.Brake(); // yes.. this is only going to brake for a few dozen uS...
lane0State = REVERSING;
lane0FeedEdge = 0;
lane0LastEdge = LN0_FEEDGATE;
// go backwards till we smack the stop
feedMotor0.Reverse();
}
/*****************************************************************************
**** LANE 1 FEED CONTROL
*****************************************************************************/
void setLane1Picking()
{
lane1State = PICKING;
//todo: PwmOut
SOLENOID_1 = 1;
}
void setLane1Feeding()
{
lane1State = FEEDING;
lane1FeedEdge = 0;
lane1LastEdge = LN0_FEEDGATE;
// solenoid release
SOLENOID_1 = 0;
lane1Feed = 1;
// motor on
feedMotor1.Forward();
}
void setLane1Reversing()
{
feedMotor1.Brake(); // yes.. this is only going to brake for a few dozen uS...
lane1Feed = 0;
lane1State = REVERSING;
lane1FeedEdge = 0;
lane1LastEdge = LN0_FEEDGATE;
// go backwards till we smack the stop
feedMotor1.Reverse();
}
void coastLane0()
{
if (lane0State == IDLE)
{
feedMotor0.Coast();
}
}
void coastLane1()
{
if (lane1State == IDLE)
{
feedMotor1.Coast();
}
}
void stopLane0Reverse()
{
feedMotor0.Brake();
lane0Feedout.attach(&coastLane0, 0.010);
}
void stopLane1Reverse()
{
feedMotor1.Brake();
lane1Feedout.attach(&coastLane1, 0.010);
}
/*****************************************************************************
**** MAIN
*****************************************************************************/
int main()
{
// solenoids off
SOLENOID_0 = 0;
SOLENOID_1 = 0;
// motors high impedance
feedMotor0.Coast();
feedMotor1.Coast();
tapeMotor0.Coast();
tapeMotor1.Coast();
LED_0 = 1;
LED_1 = 1;
// give me time to get serial port connected
wait(2);
LED_0 = 0;
LED_1 = 0;
// clear terminal screen - ignore compiler warning
pc.printf("\x1Bc\x1B[2J");
pc.printf("\r\nFeeder POST...\r\n\r\n");
UID feederID = IAP_ReadUID();
pc.printf("Feeder UID: {%#10x-%#10x-%#10x-%#10x }\r\n\r\n", feederID.word0, feederID.word1, feederID.word2, feederID.word3);
pc.printf("Gate 0 (L0 Feed): %d\r\n", LN0_FEEDGATE.read());
pc.printf("Gate 1 (L1 Feed): %d\r\n", LN1_FEEDGATE.read());
pc.printf("Gate 2 (L0 Tape): %d\r\n", LN0_TAPEGATE.read());
pc.printf("Gate 3 (L1 Tape): %d\r\n", LN1_TAPEGATE.read());
pc.printf("\r\n---\r\n");
pc.printf("Green Button 0 (L0): %d\r\n", BUTTON_GREEN_0.read());
pc.printf("Green Button 1 (L1): %d\r\n", BUTTON_GREEN_1.read());
pc.printf("Yellow Button 0 (L0): %d\r\n", BUTTON_YELLOW_0.read());
pc.printf("Yellow Button 1 (L1): %d\r\n", BUTTON_YELLOW_1.read());
pc.printf("\r\n---\r\n");
pc.printf("Lane 0 Control: %d\r\n", LANEIN_0.read());
pc.printf("Lane 1 Control: %d\r\n", LANEIN_0.read());
pc.printf("\r\n---\r\n");
pc.printf("END\r\n\r\n");
// make sure motors are at their end stops
feedMotor0.Reverse();
wait_ms(50);
feedMotor0.Coast();
// one after another, stall current is ~750mA per motor
feedMotor1.Reverse();
wait_ms(50);
feedMotor1.Coast();
// cover tape pickup interrupts
/* Moved to main loop
LN0_TAPEGATE.rise(&L0_Tape_int);
LN0_TAPEGATE.fall(&L0_Tape_int);
LN1_TAPEGATE.rise(&L1_Tape_int);
LN1_TAPEGATE.fall(&L1_Tape_int);
*/
// button/gate state temp
int b0 = 0;
int b1 = 0;
uint8_t c = 0;
// timer for button debouncing. oldass hardware buttons are bouncy!
Timer button0Time;
Timer button1Time;
float t0 = 0;
float t1 = 0;
while(true)
{
/**********************************************************************
** PC USB COMMS - 2.01uS
**********************************************************************/
// no pc comms checking when feeding, no need
if ((lane0State == IDLE || lane0State == PICKING) && (lane1State == IDLE || lane1State == PICKING))
{
while (pc.readable())
{
c = pc.getc();
pc.putc(c);
switch (pcCommand)
{
case READYFORCOMMAND:
if (c == 'F')
{
pcCommand = FEED;
pc.printf("\r\nFeed: ");
}
else if (c == 'P')
{
pcCommand = PICK;
pc.printf("\r\nPick: ");
}
else if (c == 'E')
{
pcCommand = CLOSE;
pc.printf("\r\nClose: ");
}
else if (c == 'C')
{
pcCommand = CONFIG;
pc.printf("\r\nConfig: ");
}
break;
case FEED:
if (c == '0')
{
pc.printf("\rLane 0 Feeding\r\n");
setLane0Feeding();
}
else if (c == '1')
{
pc.printf("\rLane 1 Feeding\r\n");
setLane1Feeding();
}
pcCommand = READYFORCOMMAND;
break;
case PICK:
if (c == '0')
{
pc.printf("\rLane 0 Picking\r\n");
setLane0Picking();
}
else if (c == '1')
{
pc.printf("\rLane 1 Picking\r\n");
setLane1Picking();
}
pcCommand = READYFORCOMMAND;
break;
case CLOSE:
if (c == '0')
{
pc.printf("\rLane 0 Closing\r\n");
SOLENOID_0 = 0;
lane0State = IDLE;
}
else if (c == '1')
{
pc.printf("\rLane 1 Closing\r\n");
SOLENOID_1 = 0;
lane1State = IDLE;
}
pcCommand = READYFORCOMMAND;
break;
case CONFIG:
pcCommandPos++;
if (pcConfig == NONE)
{
if (c == 'L')
pcConfig = LANE;
else
pcCommand = READYFORCOMMAND;
}
else if (pcConfig == LANE && selectedLane == UNSELECTED)
{
if (c == '0')
selectedLane = ZERO;
else if (c == '1')
selectedLane = ONE;
else
{
pcCommand = READYFORCOMMAND;
pcConfig = NONE;
}
}
else if (pcConfig == LANE)
{
if (selectedLane == ZERO)
lane0FeedDistance = c == '1' ? 1 : 2;
else
lane1FeedDistance = c == '1' ? 1 : 2;
selectedLane = UNSELECTED;
pcCommand = READYFORCOMMAND;
pcConfig = NONE;
}
break;
default:
break;
}
}
}
/**********************************************************************
** BUTTON CHECK - 3.65uS
**********************************************************************/
if (lane0State != FEEDING)
{
b0 = BUTTON_GREEN_0; // read states
b1 = BUTTON_GREEN_1;
// BUTTON 0
if (b0 == button0LastState && b0) // button0 is pressed and was pressed last time too
{
if (lane0State == IDLE)
{
if (button0Time.read_ms() > 100) // wait for button state to be stable for 100ms
{
button0Time.reset();
button0Time.stop(); // no need to keep counting
pc.printf("Picking 0\r\n");
setLane0Picking(); // open solenoid while button is down
}
}
}
else if (!b0 && b0 != button0LastState) // low transition - button released
{
button0LastState = b0;
if (lane0State == PICKING) // not just a bounce
{
pc.printf("Feeding 0\r\n");
setLane0Feeding(); // button has been released, feed one component
}
}
else // high transition
{
if (b0) // button pressed
{
button0Time.reset();
button0Time.start();
}
}
button0LastState = b0;
}
if (lane1State != FEEDING)
{
// BUTTON 1
if (b1 == button1LastState && b1) // button0 is pressed and was pressed last time too
{
if (lane1State == IDLE)
{
if (button1Time.read_ms() > 100)
{
button1Time.reset();
button1Time.stop();
pc.printf("Picking 1\r\n");
setLane1Picking();
}
}
}
else if (!b1 && b1 != button1LastState) // low transition - button released
{
button1LastState = b1;
if (lane1State == PICKING)
{
pc.printf("Feeding 1\r\n");
setLane1Feeding();
}
}
else // high transition
{
if (b1)
{
button1Time.reset();
button1Time.start();
}
button1LastState = b1;
}
}
/**********************************************************************
** ENCODER CHECK - 3.38uS
**********************************************************************/
b0 = LN0_FEEDGATE;
b1 = LN1_FEEDGATE;
// LANE 0
if (lane0State == FEEDING || lane0State == REVERSING)
{
if (lane0LastEdge != b0)
{
lane0FeedEdge++;
}
}
lane0LastEdge = b0;
// off stop, gap, past stop
if (lane0State == FEEDING &&
lane0FeedEdge > (lane0FeedDistance * FEED_FWD_ENC_PULSE))
{
lane0FeedEdge = 0;
feedMotor0.Brake();
pc.printf("R0\r\n");
setLane0Reversing();
}
// gap, return to stop
else if (lane0State == REVERSING && lane0FeedEdge > 1)
{
lane0State = IDLE;
lane0Feedout.attach(&stopLane0Reverse, 0.020);
pc.printf("Idle 0\r\n");
}
// LANE 1
if (lane1State == FEEDING || lane1State == REVERSING)
{
if (lane1LastEdge != b1)
{
lane1FeedEdge++;
}
}
lane1LastEdge = b1;
// off stop, gap, past stop
if (lane1State == FEEDING &&
lane1FeedEdge > (lane1FeedDistance * FEED_FWD_ENC_PULSE))
{
lane1FeedEdge = 0;
feedMotor1.Brake();
pc.printf("R1\r\n");
setLane1Reversing();
}
// gap, return to stop
else if (lane1State == REVERSING && lane1FeedEdge > 1)
{
lane1State = IDLE;
lane1Feedout.attach(&stopLane1Reverse, 0.020);
pc.printf("Idle 1\r\n");
}
LED_0 = 1;
/**********************************************************************
** COVER TAPE CHECK - Gate closed: 41.98uS, Gate open 30.48uS
**********************************************************************/
b0 = LN0_TAPEGATE;
b1 = LN1_TAPEGATE;
if (tape0Takeup)
t0 = tape0PullTime.read(); // very slow..
if (tape1Takeup)
t1 = tape0PullTime.read(); // very slow..
// LANE 0
if (!b0 && !tape0Takeup) // cover tape slacked enough to interrupt gate
{
tape0PullTime.reset();
tape0PullTime.start();
tape0Takeup = 1;
tapeMotor0.Forward();
}
else if ((b0 && t0 > TAPE_MIN_PULL_TIME) ||
(!b0 && tape0Takeup && t0 > TAPE_MAX_PULL_TIME))
{
stopTapeL0();
}
// LANE 1
if (!b1 && !tape1Takeup) // gate opened
{
tape1PullTime.reset();
tape1PullTime.start();
tape1Takeup = 1;
tapeMotor1.Forward();
}
else if ((b1 && t1 > TAPE_MIN_PULL_TIME) ||
(!b1 && tape1Takeup && t1 > TAPE_MAX_PULL_TIME))
{
stopTapeL1();
}
LED_0 = 0; // for timing check
}
}