Hi folks:
The experts among us are very tired of solving timer and delay issues and I understand. However, I have a bit of a twist on the issue and could use some help.
I have a pan/tilt device (actually four) with Arduino, stepper motors and on one, a zoom servo. I'll put my very cumbersome code below.
My twist is this: I need to have smooth camera pans so I have a slow speed programmed to the joystick. I set up a routine that if the joystick (-500 to 500) passes ±450, the motors kick into high speed so that if I need a quick shot of the audience it doesn't take 20 seconds for the camera to swing 150°. The problem is if the operator gets a little heavy handed, the camera switches speeds suddenly. Ideally, I would program in a one or two second delay (counter or milliseconds) for the speed change, so if the joystick gets past 450 for a moment but doesn't stay, it is still smooth. If the joystick is railed for more than the delay time, it can kick into high speed. If the operator leans heavily on the joystick for a moment, it will not jolt into the high speed. If the operator KEEPS the joystick railed, however, it will react and go at its highest speed.
I have a routine in the code to kick into this high speed when the joystick is past ±450, but I have commented it out. I tried to use a counting variable "j," but it didn't seem to be working, partly because I'm unclear where the j=1 reset should be, and don't know whether to use an "if joystick is >450" function or "while joystick >450" function to count up j=++j.
Any ideas?
#include <AccelStepper.h> //accelstepper library
AccelStepper stepper(1, 8, 9); // pulses Digital 8 (STEP), direction Digital 9 (CCW)
AccelStepper stepperY(1, 10, 11); // pulses Digital 10 (STEP), direction Digital 11 (CCW)
// include the Servo library
#include <Servo.h>
Servo myServo; // create a servo object
/*Author's notes
This version is for Camera 3 with Servo
This version (111) will use
max motor speed * .5
high speed at end of joystick
High Speed disabled 2/13/22 Too bouncy
Using Pololu A4988 at 1/16th step
MS1 MS2 MS3
L L L Full Step
H L L Half Step
L H L Quarter Step
H H L Eighth Step
H H H Sixteenth Step
*/
//Pins
const byte Analog_X_pin = A0; //x-axis readings
const byte Analog_Y_pin = A1; //y-axis readings
const byte homeSetpin = 2; //set home to 0
const byte homeGopin = 3; //go home switch
int redPin = 4; //Red LED pin
int const potPin = A2; // analog pin used to connect the potentiometer for the servo
int servoPin = 12; // Output servoAngle to servo
const byte initializeButton = 7; //Button 3
//Motor data
int enPin = 5;
int enPinY = 6;
int stepPin = 8; // Pan Direction
int dirPin = 9; // Step
int stepPinY = 10; //Tilt direction
int dirPinY = 11; //Tilt step
int accelRate = 2000; //mostly for Go Home routine
int motSpeed = 0;
int motSpeedY = 0;
int speedMult = 1;
int speedMultY;
int valAway = 100; // Value away from center before Joystick works
int valAwayServo = 15; // Value away from center before servo moves
int servoRange = 40; // Max deviation of servo from 90
int valAwayFix;
int valAwayFixY;
int speedShift = 450;
int maxSpeed_val = 1000;
int maxSpeed_valY = 1000;
int startPos = 0;
int stepsPerRev = 3200;
int newPos = 20;
int yButtonOld = 1;
int yMotorState = 1;
int xMotorState = -1;
int hiSpeed = 950;
int xSpeedFactor = 2;
int ySpeedFactor = 4;
// Boundary Limits
long highMax = 1200;
long lowMax = -1200;
long highMaxY = 700;
long lowMaxY = -700;
int safePos = 0;
//Variables
int Analog_X = 0; //x-axis value
int Analog_Y = 0; //y-axis value
int homeSet_Val; //switch value
int homeGo_Val ; //switch value
int initializeButton_Val = 1; //joystick button switch
int Analog_X_AVG = 0; //x-axis value average
int Analog_Y_AVG = 0; //y-axis value average
int Analog_S_AVG = 512; //servo pot value average
int potVal; // variable to read the value from the analog pin
int servoAngle; // variable to hold the servoAngle for the servo motor
int servoCenter = 90; //Servo at rest
//int homeGo_Val_Value = 0; //
//Time variables
unsigned long refMillis;
unsigned long currentMillis;
unsigned long stoppedMillis;
unsigned long speedCount = 200000; //j counter for high speed X
const unsigned long period = 1000; //the value is a number of milliseconds, ie 1 second
int j; //counter one
int j2; //counter two
long j3; //counter three
long j3Max = 10003; //counter three reset
int speedDiff;
int speedDiffY;
int printCount = 1;
int glacierT = 100;
int dt = 1000;
int ydt = 100; //ybutton delay
unsigned long pauseT;
unsigned long pauseTY;
unsigned long pauseMax = 350;
unsigned long pauseMaxY = 350;
void setup()
{
//SERIAL
Serial.begin(9600);
Serial.println ("Begin Sketch");
//----------------------------------------------------------------------------
//PINS
pinMode(Analog_X_pin, INPUT);
pinMode(Analog_Y_pin, INPUT);
pinMode(initializeButton, INPUT);
pinMode(homeSetpin, INPUT);
pinMode(homeGopin, INPUT);
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(dirPinY, OUTPUT);
pinMode(stepPinY, OUTPUT);
pinMode(enPin, OUTPUT);
pinMode(enPinY, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(potPin, INPUT);
digitalWrite(enPin, HIGH); // disable motor
digitalWrite(enPinY, HIGH); // disable motor
Serial.println("disabled before setup");
digitalWrite (homeSetpin, HIGH);
digitalWrite (homeGopin, HIGH);
digitalWrite (initializeButton, HIGH);
digitalWrite(redPin, LOW); // turn off redLED
myServo.attach(12); // attaches the servo on pin 12 to the servo object
//----------------------------------------------------------------------------
InitialValues(); //averaging the values of the 3 analog pins (values from potmeters)
//----------------------------------------------------------------------------
//Stepper parameters
//setting up some default values for maximum speed and maximum acceleration
stepper.setCurrentPosition(0);
stepper.setMaxSpeed(maxSpeed_val); //SPEED = Steps / second
stepper.setAcceleration(accelRate); //ACCELERATION = Steps /(second)^2
stepper.setSpeed(0);
// stepperY
stepperY.setCurrentPosition(0);
stepperY.setMaxSpeed(maxSpeed_val); //SPEED = Steps / second
stepperY.setAcceleration(accelRate); //ACCELERATION = Steps /(second)^2
stepperY.setSpeed(0);
//----------------------------------------------------------------------------
refMillis = millis(); //initial start time
Serial.println ("Let's GO!");
}
//-----------------------------------------
//------------ Void Loop -----
//-----------------------------------------
void loop() {
// put your main code here, to run repeatedly:
Analog_X = analogRead(Analog_X_pin);
Analog_Y = analogRead(Analog_Y_pin);
homeSet();
homeGo();
checkBoundary();
servoCheck();
initializeButton_Val = digitalRead(initializeButton); //recalibrates joystick
if (initializeButton_Val == 0)
{
InitialValues();
}
//if the value is valAway "value away" from the average (midpoint), we allow the update of the speed
//This is a sort of a filter for the inaccuracy of the reading
//-----------------------------------------
//------------ X Motor Speed -----
//-----------------------------------------
if (abs(Analog_X - Analog_X_AVG) > valAway)
{
speedMult = abs(Analog_X - Analog_X_AVG) / (Analog_X - Analog_X_AVG); //yields +1 or -1 factor
valAwayFix = valAway * speedMult;
motSpeed = (((Analog_X - Analog_X_AVG) - valAwayFix) * xMotorState) / xSpeedFactor; //Set left/right
stepper.runSpeed(); //step the motor (this will step the motor by 1 step at each loop indefinitely)
// digitalWrite(enPin, LOW); // enable motor
stepper.setSpeed(motSpeed);
stepper.runSpeed();
/*
if (abs(Analog_X - Analog_X_AVG) > speedShift)
{
j=++j;
if (j > speedCount);
{
motSpeed = (maxSpeed_val / 2) * (motSpeed / (abs(motSpeed)));
stepper.setSpeed(motSpeed);
stepper.runSpeed();
}
}
else
{
j = 1;
}
*/
//----------------X Motor Print-----------------------
currentMillis = millis(); //
if (currentMillis - refMillis >= period) //test whether the period has elapsed
{
Serial.print ("Analog_X= ");
Serial.print (Analog_X);
Serial.print (" Current Position X =");
Serial.print (stepper.currentPosition());
Serial.print (" motSpeed X = ");
Serial.println (motSpeed);
refMillis = currentMillis; //IMPORTANT to save the start time of the speed printout.
}
else
{
motSpeed = 0;
printCount = 1; //reset for homeGo routine
}
} //---------------------------end Analog_X val check
//-----------------------------------------
//------------ Y Motor Speed -----
//-----------------------------------------
if (abs(Analog_Y - Analog_Y_AVG) > valAway)
{
speedMultY = abs(Analog_Y - Analog_Y_AVG) / (Analog_Y - Analog_Y_AVG);
valAwayFixY = valAway * speedMultY;
motSpeedY = ((Analog_Y - Analog_Y_AVG - valAwayFixY) * yMotorState) / ySpeedFactor; //determines flightStick or gamerStick
stepperY.runSpeed();
stepperY.setSpeed(motSpeedY);
stepperY.runSpeed();
/*
if (abs(Analog_Y - Analog_Y_AVG) > speedShift) // Full speed at end of joystick
{
motSpeedY = (maxSpeed_valY/2) * (motSpeedY / (abs(motSpeedY))); //get sign of motor speed
stepperY.setSpeed(motSpeedY);
// stepperY.runSpeed();
stepperY.run();
}
*/
//----------Y motor print -------------
currentMillis = millis(); //
if (currentMillis - refMillis >= period) //test whether the period has elapsed
{
Serial.print ("Analog_ Y= ");
Serial.print (Analog_Y);
Serial.print (" Current Position Y =");
Serial.print (stepperY.currentPosition());
Serial.print (" motSpeed Y = ");
Serial.println (motSpeedY);
refMillis = currentMillis; //IMPORTANT to save the start time of the speed printout.
}
}
else
{
motSpeedY = 0;
}
j3 = ++j3;
if (j3 >= j3Max) //test whether the period has elapsed
{
Serial.print (j3);
Serial.print (" Waiting on Joystick X & Y= ");
Serial.print (Analog_X);
Serial.print (" ");
Serial.print (Analog_Y);
Serial.print (" motSpeed X&Y = ");
Serial.print (motSpeed);
Serial.print (" ");
Serial.println (motSpeedY);
Serial.print("potVal: ");
Serial.print(potVal);
Serial.print(", servoAngle: ");
Serial.println(servoAngle);
j3 = 1; //IMPORTANT to save the start time of the speed printout.
}
} // end void loop
//----------------------------------------\
//----------- ROUTINES ------------->
//----------------------------------------/
//-------------------------------------------
//----------- Initial Values() -----
//------------------------------------------
void InitialValues()
{
blinkRed();
stepper.setSpeed(0);
stepperY.setSpeed(0);
motSpeed = 0;
motSpeedY = 0;
// digitalWrite(enPin, HIGH); // disable motor
//Set the values to zero before averaging
float tempX = 0;
float tempY = 0;
float tempS = 0;
//----------------------------------------------------------------------------
//read the analog 50x, then calculate an average.
//they will be the reference values
for (int i = 0; i < 50; i++)
{
tempX += analogRead(Analog_X_pin);
delay(10); //allowing a little time between two readings
tempY += analogRead(Analog_Y_pin);
delay(10);
tempS += analogRead(potPin);
delay(10);
}
//----------------------------------------------------------------------------
Analog_X_AVG = tempX / 50;
Analog_Y_AVG = tempY / 50;
Analog_S_AVG = tempS / 50;
digitalWrite(enPin, HIGH); // disable motor
digitalWrite(enPinY, HIGH); // disable motor
//----------------------------------------------------------------------------
Serial.print("AVG_X: ");
Serial.println(Analog_X_AVG);
Serial.print("AVG_Y: ");
Serial.println(Analog_Y_AVG);
Serial.print("AVG_S: ");
Serial.println(Analog_S_AVG);
Serial.println("Calibration finished, still disabled");
// two blinks
blinkRed();
delay(ydt * 4);
blinkRed();
}
//-------------------------------------------
//----------- blinkRed() -----
//------------------------------------------
void blinkRed() //Red LED Blink
{
digitalWrite(redPin, HIGH);
delay(ydt);
digitalWrite(redPin, LOW);
}
//-------------------------------------------
//----------- homeSet() ------------
//------------------------------------------
void homeSet()
{
homeSet_Val = digitalRead(homeSetpin);
if (homeSet_Val == 0) //set home location
{
blinkRed();
stepper.setCurrentPosition(0); // Set the current position as zero for now
Serial.print("Home - X");
stepper.setMaxSpeed(maxSpeed_val); //SPEED = Steps / second
stepper.setAcceleration(accelRate); //ACCELERATION = Steps /(second)^2
stepper.setSpeed(motSpeed);
stepper.runSpeed();
stepperY.setCurrentPosition(0); // Set the current position as zero for now
Serial.print(" Home - Y");
digitalWrite(enPin, LOW); // enable X motor
digitalWrite(enPinY, LOW); // enable Y motor
Serial.println(" Motors Enabled by Home Switch");
stepperY.setMaxSpeed(maxSpeed_val); //SPEED = Steps / second
stepperY.setAcceleration(accelRate); //ACCELERATION = Steps /(second)^2
stepperY.setSpeed(motSpeed);
stepperY.runSpeed();
// myServo.write(servoCenter);
}
}
//-------------------------------------------
//----------- homeGo() ------------
//------------------------------------------
void homeGo()
{
homeGo_Val = digitalRead (homeGopin);
if (homeGo_Val == 0) // Go Home
{
blinkRed();
speedMult = abs (stepper.currentPosition()) / stepper.currentPosition();
speedMultY = abs (stepperY.currentPosition()) / stepperY.currentPosition();
Serial.print (stepper.currentPosition());
Serial.print (" X < Going Home > Y ");
Serial.println (stepperY.currentPosition());
stepper.moveTo (0);
motSpeed = (maxSpeed_val * .5);
motSpeedY = (maxSpeed_val * .5);
stepper.setSpeed(motSpeed);
stepperY.moveTo (0);
stepperY.setSpeed(motSpeedY);
while (stepper.currentPosition() != stepper.targetPosition())
{
// stepper.runSpeedToPosition();
stepper.runToPosition();
}
while (stepperY.currentPosition() != stepperY.targetPosition())
{
// stepperY.runSpeedToPosition();
stepperY.runToPosition();
}
}
// If move is completed display message on Serial Monitor
if ((stepper.distanceToGo() == 0 && printCount < 2))
{
Serial.println("Now Home!");
motSpeed = 0;
motSpeedY = 0;
printCount = printCount + 1;
}
}
//----------------------------------------------------------------------------
// checkBoundary()
//----------------------------------------------------------------------------
void checkBoundary() //Protection from over rotation
{
//---------------- X Boundary
if (stepper.currentPosition() <= lowMax || stepper.currentPosition() >= highMax)
{
stepper.setSpeed(0);
Serial.print ("Over Rotated ");
Serial.println (stepper.currentPosition());
delay (dt);
}
if (stepper.currentPosition() <= lowMax) // Negative Overrotation
{
safePos = (lowMax + 100);
stepper.moveTo (safePos);
stepper.setSpeed(maxSpeed_val / 4);
while (stepper.currentPosition() != stepper.targetPosition())
{
stepper.runSpeedToPosition();
}
}
if (stepper.currentPosition() >= highMax) // Positive Overrotation
{
safePos = (highMax - 100);
stepper.moveTo (safePos);
stepper.setSpeed(maxSpeed_val / 4);
while (stepper.currentPosition() != stepper.targetPosition())
{
stepper.runSpeedToPosition();
}
}
//----------- Y Boundary
if (stepperY.currentPosition() <= lowMaxY || stepperY.currentPosition() >= highMaxY)
{
stepperY.setSpeed(0);
Serial.print ("Over Rotated ");
Serial.println (stepperY.currentPosition());
delay (dt);
}
if (stepperY.currentPosition() <= lowMaxY) // Negative Overrotation
{
safePos = (lowMaxY + 100);
stepperY.moveTo (safePos);
stepperY.setSpeed(maxSpeed_val / 4);
while (stepperY.currentPosition() != stepperY.targetPosition())
{
stepperY.runSpeedToPosition();
}
}
if (stepperY.currentPosition() >= highMaxY) // Positive Overrotation
{
safePos = (highMaxY - 100);
stepperY.moveTo (safePos);
stepperY.setSpeed(maxSpeed_val / 4);
while (stepperY.currentPosition() != stepperY.targetPosition())
{
stepperY.runSpeedToPosition();
}
}
}
//----------------------------------------------------------------------------
// servoCheck()
//----------------------------------------------------------------------------
void servoCheck()
{
potVal = analogRead(potPin); // read the value of the potentiometer
// scale the numbers from the pot
servoAngle = map(potVal, 0, 1023, (90 + servoRange), (90 - servoRange));
if (abs(potVal - Analog_S_AVG) > valAwayServo)
{ // set the servo position
myServo.write(servoAngle);
}
else {
// servoAngle = 90;
myServo.write(servoCenter);
}
/* while (abs(potVal - Analog_S_AVG) <= valAwayServo)
{
myServo.write(servoCenter);
}
*/
}