//
// AutoLoc Linear Actuator Control Software
//
// AutoLoc linear actuators use a DC motor and simple polarity reversing to extend
// and retract. They also feature a hall effect sensor that sends pulses as it moves.
//
// http://www.carid.com/images/autoloc/vertical-doors/pdf/la24-installation-instructions.pdf
//
// This code taken from:
// http://forum.arduino.cc/index.php?topic=236470.0
// which originally took the code from here:
// http://learn.robotgeek.com/demo-code/123-arduino-linear-actuator-tutorial-preset-position-button-control.html
//
//
unsigned long lastStepTime = 0; // Time stamp of last pulse
int trigDelay = 500;
int resetdelay = 2000;
const int relay1 = 8; // extend relay output pin connection
const int relay2 = A5; // retract relay output pin connection
const int HALL0 = 2; // interupt pin connection - See attachInterrupt() docs for your board
unsigned long prevTimer; //some global variables available anywhere in the program
unsigned long startMillis;
const unsigned long pause = 3000;
volatile int counter = 0;
int counterState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
long lastDebounce0 = 0;
long debounceDelay = 10; // Ignore bounces under 10ms
volatile int CurrentPosition = 0;
int goalPosition = 0;
int lastgoalPosition = 0;
boolean Extending = false;
boolean Retracting = false;
// void actuatorExtend(){
// digitalWrite(relay1, HIGH); // Always turn one off and then the other on
// digitalWrite(relay2, LOW); // so that there are never two relays on (BIG!)
// }
// void actuatorRetract(){
// digitalWrite(relay2, HIGH); // Always turn one off and then the other on
// digitalWrite(relay1, LOW); // so that there are never two relays on (BIG!)
// }
// void actuatorStop() {
// digitalWrite(relay2, HIGH);
// digitalWrite(relay1, HIGH);
// }
#define NUM_FWD_GEARS 7
#define BUTTON_READ_INTERVAL 50ul //mS time between up/down button reads
#define NO_PRESS 0x00 //mask bit mask for no buttons pressed
#define BUTTON_UP_PRESSED 0x01 //mask bit mask for up button pressed
#define BUTTON_DOWN_PRESSED 0x02 //mask bit mask for down button pressed
#define TCC_DELAY 1000ul //mS after TCC is enabled, time delay before activation
const byte buttonUP = A0; //pin Push Button for UP shift
const byte buttonDOWN = A2; //pin Push Button for Down shift
const byte switchTOWMODE = 7; //pin Switch for tow/haul mode
const byte solA = 9; //pin Solenoid A output
const byte solB = 10; //pin Solenoid B output
const byte TCC = 6; //pin TCC output
int incomingByte;
byte
gearSelection,
lastGearSelection,
lastUp,
lastDn,
lastTM;
// Park,
// Reverse,
// Neutral,
// First,
// Second,
// Third,
// Fourth;
bool
bTCCStatus;
unsigned long
timeTCCSolenoid;
typedef struct structGearSolenoidProfiles
{
byte goalPosition;
byte solenoid_A;
byte solenoid_B;
bool bTCCGearEnable;
}sGearSolenoidProfiles;
enum {Park, Reverse,Neutral,First,Second,Third,Fourth};
//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] =
{
{
//Park,
goalPosition = 0,
.solenoid_A = HIGH,
.solenoid_B = LOW,
.bTCCGearEnable = false
},
{
//Reverse,
goalPosition = 200,
.solenoid_A = LOW,
.solenoid_B = LOW,
.bTCCGearEnable = false
},
{
//Neutral,
goalPosition = 375,
.solenoid_A = HIGH,
.solenoid_B = LOW,
.bTCCGearEnable = false
},
{
//First,
goalPosition = 525,
.solenoid_A = LOW,
.solenoid_B = LOW,
.bTCCGearEnable = false
},
{
//Second,
goalPosition = 525,
.solenoid_A = LOW,
.solenoid_B = HIGH,
.bTCCGearEnable = false
},
{
//Third,
goalPosition = 525,
.solenoid_A = LOW,
.solenoid_B = HIGH,
.bTCCGearEnable = true
},
{
//Fourth,
goalPosition = 525,
.solenoid_A = HIGH,
.solenoid_B = HIGH,
.bTCCGearEnable = true
}
};//GearSolenoidProfiles[]
void actuatorExtend(){
digitalWrite(relay1, LOW); // Always turn one off and then the other on
digitalWrite(relay2, HIGH); // so that there are never two relays on (BIG!)
}
void actuatorRetract(){
digitalWrite(relay2, LOW); // Always turn one off and then the other on
digitalWrite(relay1, HIGH); // so that there are never two relays on (BIG!)
}
void actuatorStop() {
digitalWrite(relay2, HIGH);
digitalWrite(relay1, HIGH);
}
void setup()
{
pinMode( buttonUP, INPUT_PULLUP );
lastUp = digitalRead( buttonUP ); //set initial button state
pinMode( buttonDOWN, INPUT_PULLUP );
lastDn = digitalRead( buttonDOWN ); //set initial button state
pinMode( switchTOWMODE, INPUT_PULLUP );
pinMode( solA, OUTPUT ); //Solenoid A set as output
pinMode( solB, OUTPUT ); //Solenoid B set as output
pinMode( TCC, OUTPUT ); //TCC set as output
digitalWrite( solA, LOW ); //set intital state as off
digitalWrite( solB, LOW );
digitalWrite( TCC, LOW );
//internal flag for TCC status
bTCCStatus = false;
gearSelection = 0; //start in "1st" gear for this test
lastGearSelection = 0xff; //ensure we change into correct gear first pass by making last != current
Serial.begin(9600);
pinMode(HALL0, INPUT); // reedSwitch is an input
attachInterrupt(1, trigger0, RISING); // See attachInterrupt() doc for YOUR BOARD
// Set both output pins
pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
// Initialize both relays to off (make sure whatever relay setup you use defaults
// to OFF since there may be some delay between power-up and this code executing!
digitalWrite(relay2, HIGH);
digitalWrite(relay1, HIGH);
}
void actuator(void)
{
if (Extending == true && CurrentPosition > goalPosition ) {
actuatorStop();
Extending = false;
}
if (Retracting == true && CurrentPosition < goalPosition) {
actuatorStop();
Retracting = false;
}
// if (Serial.available() > 0) {
// // read the oldest byte in the serial buffer:
// incomingByte = Serial.read();
if ((GearSolenoidProfiles[gearSelection].goalPosition)> CurrentPosition) {
//if (goalPosition = ""); {
//if (goalPosition > CurrentPosition) {
Retracting = false;
Extending = true;
actuatorExtend ();
Serial.println(CurrentPosition);
Serial.print(counter);
}
else if ((GearSolenoidProfiles[gearSelection].goalPosition)< CurrentPosition) { //(goalPosition < CurrentPosition) {
Retracting = true;
Extending = false;
actuatorRetract();
Serial.print(CurrentPosition);
Serial.print(counter);
}
if (incomingByte == 'S') {
actuatorStop();
Serial.println("Stop");
}
}
// if (incomingByte == 'B') {
// goalPosition = 200;
// if (CurrentPosition < goalPosition ) {
// Retracting = false;
// Extending = true;
// actuatorExtend ();
// Serial.println("BExtending");
// }
// else if (goalPosition < CurrentPosition) {
// Retracting = true;
// Extending = false;
// actuatorRetract();
// Serial.println("BRetracting");
// }
// }
// if (incomingByte == 'C') {
// goalPosition = 400;
// if (goalPosition > CurrentPosition) {
// Retracting = false;
// Extending = true;
// actuatorExtend ();
// Serial.println("AExtending");
// }
// else if (goalPosition < CurrentPosition) {
// Retracting = true;
// Extending = false;
// actuatorRetract();
// Serial.println("ARetracting");
// }
// }
// if (incomingByte == 'D') {
// goalPosition = 525;
// if (CurrentPosition < goalPosition ) {
// Retracting = false;
// Extending = true;
// actuatorExtend ();
// Serial.println("BExtending");
// }
// else if (goalPosition < CurrentPosition) {
// Retracting = true;
// Extending = false;
// actuatorRetract();
// Serial.println("BRetracting");
// }
// }
void loop(void) {
actuator();
trigger0();
Gear_Selection_Control();
Gear_Solenoid_Control();
TCC_Control();
}//loop
// Once we start a relay, we should start getting pulses from the sensor as the
// actuator moves. When we get a RISING edge and interrupt will be generated and
// we will jump to the following function.
void trigger0() {
if ( (millis() - lastDebounce0) > debounceDelay && Extending == true) {
counter++;
Serial.print(counter);
Serial.println(" : ");
CurrentPosition = counter;
lastDebounce0 = millis();
}
if ( (millis() - lastDebounce0) > debounceDelay && Retracting == true) {
counter--;
Serial.println(counter);
Serial.print(" : ");
CurrentPosition = counter;
lastDebounce0 = millis();
}
}
// if ( Extending == true) {
// counter++;
// CurrentPosition = counter;
// }
// if ( Retracting == true ) {
// counter--;
// CurrentPosition = counter;
// }
// }
void Gear_Selection_Control( void )
{
byte
btnState;
btnState = ReadButtons();
switch( btnState )
{
case NO_PRESS:
//nothing pressed or not read (interval not elapsed); no action
break;
case BUTTON_UP_PRESSED:
if( gearSelection < (NUM_FWD_GEARS-1) )
gearSelection++;
break;
case BUTTON_DOWN_PRESSED:
if( gearSelection > 0 )
gearSelection--;
break;
default:
//only remaining possibility is both pressed; ignore with no action
break;
}//switch
}//void
void Gear_Solenoid_Control( void )
{
if( gearSelection != lastGearSelection )
{
lastGearSelection = gearSelection;
digitalWrite( solA, GearSolenoidProfiles[gearSelection].solenoid_A );
digitalWrite( solB, GearSolenoidProfiles[gearSelection].solenoid_B );
//if
// - the gear just selected enables the TCC, and
// - the last gear did not enable it, and
// - the TCC is not now enaged
// start the TCC delay timer
if( bTCCStatus == false )
{
if( GearSolenoidProfiles[gearSelection].bTCCGearEnable == true &&
GearSolenoidProfiles[lastGearSelection].bTCCGearEnable == false )
{
timeTCCSolenoid = millis();
}//if
}//if
}//if
}//Gear_Control
void TCC_Control( void )
{
unsigned long
tNow;
bool
bTCCEnabled;
tNow = millis();
//TCC enabled if:
// - 4th gear is engaged, OR
// - 3rd gear is engaged and tow-mode not selected, AND
// - TCC delay timer has expired
bTCCEnabled = ( (gearSelection == 3) ||
( (gearSelection == 2 && digitalRead( switchTOWMODE ) == HIGH) ) ) &&
( tNow - timeTCCSolenoid >= TCC_DELAY );
//if conditions passed and TCC is now off, turn on its solenoid
if( bTCCEnabled )
{
if( bTCCStatus == false )
{
//turn on TCC
digitalWrite( TCC, HIGH );
bTCCStatus = true;
}//if
}//if
else
{
if( bTCCStatus == true )
{
//turn off TCC
digitalWrite( TCC, LOW );
bTCCStatus = false;
}//if
}//else
}//TCC_Control
//returns a mask:
//0b00000000 - no buttons pressed
//0b00000001 - up pressed
//0b00000010 - down pressed
//0b00000011 - both pressed
//
byte ReadButtons( void )
{
static unsigned long
timeButton = 0;
unsigned long
tNow;
byte
retval,
nowButton;
retval = NO_PRESS;
tNow = millis();
if( (tNow - timeButton) >= BUTTON_READ_INTERVAL )
{
//set up for next read interval
timeButton = tNow;
//read the button and set the flags
nowButton = digitalRead( buttonUP );
if( nowButton != lastUp )
{
lastUp = nowButton;
if( nowButton == LOW )
retval |= BUTTON_UP_PRESSED;
}//if
nowButton = digitalRead( buttonDOWN );
if( nowButton != lastDn )
{
lastDn = nowButton;
if( nowButton == LOW )
retval |= BUTTON_DOWN_PRESSED;
}//if
}//if
return retval;
}//ReadButtons