dead band question

hi there
i have a motor and gearbox with a set of limits of ether end of its travel and a 10k pot, i have some code what drives the motor all one way to when it hits one limit thats the min value and then drives the other way and takes its max value and then maps it to 0-100, which all works fine. (the output i call sensorValue)

i also have a 0-10v input going tho a voltage divider so that gets me to 0 to 5v. also seem to work fine (the input i call where)

so when the voltage of the 0-10v increases i won't the motor to move the pot round to match
and this is what i come up with:

// pot 0-10v
if (sensorValue > where) {
if (digitalRead(vent1UPlim)== HIGH) {
DoneInitializationA=false; // resetting the count
digitalWrite(vent1enable, HIGH);
delay(50);
digitalWrite(vent1PWMA , HIGH);
mydisp.drawStr(0, 2, "-close-|");
}
else {
digitalWrite(vent1PWMA , LOW);
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}
}
else {
if (!DoneInitializationA)
{
// delay(1000); // over run time
digitalWrite(vent1PWMA , LOW);
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
DoneInitializationA=true; // Initialization is done, don't run it again until button has been low
}
}

// VENT 1 DOWN / OPEN CONTAL
if (sensorValue < where) {
if (digitalRead(vent1DOWNlim)== HIGH) {
DoneInitializationB=false; // resetting the count
digitalWrite(vent1enable, HIGH);
delay(50);
digitalWrite(vent1PWMB , HIGH);
mydisp.drawStr(0, 2, "-open -|");
}
else {
digitalWrite(vent1PWMB , LOW);
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}
}
else {
if (!DoneInitializationB)
{
// delay(1000); // over run time
digitalWrite(vent1PWMB , LOW);
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
DoneInitializationB=true; // Initialization is done, don't run it again until button has been low
}
}

what work but it hunts as it never gets it exact so i need to add a dead band into something like 2%
so how do i go about doing this?

i hope i have explained myself good enough thanks

It would seem that since you are comparing sensorValue to where that you have them both mapped to the same scale. If that is the case then how about something like...

if (sensorValue > where + 1)

And when comparing if sensorValue is less than where then use where-1.

With the values mapped 0-100 this should give a 3 value (3%) dead zone.

ok cool

if (sensorValue > where + 1)

and

if (sensorValue < where + 1) // should this still be + or -?

if (sensorValue < where - 1)

I think that will work.

Or you could use a PID loop to control the motor drive, so that you are not driving at
full rate near the target, ie you give the motor a chance to slow down and not overshoot.

Currently you appear to be using digitalWrite to the PWM controls on the motor driver,
so you are using "bang bang" drive, ie full forward or full reverse and alternating between
them with some hysteresis and overshoot, which is pretty crude.

Right you are MarkT, making motor speed proportional to distance from desired position would indeed smooth things out.

I was going to add that you are actually losing quite a bit of resolution due to mapping the analogRead() you are using to check the 0-5V down to a 0-100 scale, if both "where" and "sensorValue" were on a 0-1023 scale the control resolution would be much finer and perhaps would eliminate some hunting issues.

yer i see what you meen about the resolution

and yes PWM is a very good idea but i did not do this because i did not no how to go about that, maybe this is the time i should, what would be a good way of going about this?

thanks for your input :slight_smile:

For PWM you are going to want to use analogWrite() in place of digitalWrite(), for instance

analogWrite(vent1PWMB ,127);

Would make the motor move at 1/2 speed, 0 would be stopped, 255 full speed.

So you could do something like as a quick and dirty speed control.
if(sensorValue > where)
{
if (sensorValue - where > 10)
{
motorSpeed = 255;
}
if (sensorValue - where < 10)
{
motorSpeed = 127;
}
if (sensorValue - where < 3)
{
motorSpeed = 64;
}
}

//duplicate the checks for where>sensorValue

analogWrite(vent1PWMB ,motorSpeed);

right ok i get that.

but how do we get it to ramp up and down over time and all so looking at the pot and 0-10v?

Sorry, made another edit up there

Of course you would have to play with the numbers to optimize it.

Maybe something along these lines:

// keep both sensorValue and where in range of 0 to 1023, get the delta then shift down by 2, which
// effectively divides by 4 (more importantly takes your 0-1023 range into 0-255 that the PWM takes

int motorSpeed = ( sensorValue - where ) >> 2; 
analogWrite(vent1PWMB ,motorSpeed);

Here's how I'd do it.. I don't quite understand some of the code, but here's how I'd control the motor smoothly with a deadband where it doesn't move, so that it follows what you're doing on the pot.. that is what you're trying to accomplish right?

int MaxSpeed = 255; //The maximum speed you want to run at.. perhaps you want to not run at full speed.. values are from 0-255;
int FullSpeedPotDifference = 100; //when the values are more than this apart, you will be running at MaxSpeed
//The motor will linearly slow down from there to the deadband point, where it will stop

int Deadband = 3; //No motor output if the pots are within this value of each other
int motorPot = analogRead(InputPin1); //the pot your motor is mechanically controlled to
int controlPot = analogRead(InputPin2); //the 0-10V input
int potDifference = controlPot-motorPot;

boolean Forward = potDifference >=0;


int motorSpeed = map(abs(potDifference),Deadband,FullSpeedPotDifference,0,MaxSpeed); 

motorSpeed = constrain(motorSpeed,0,MaxSpeed); //We need to constrain it to our limits now



//if you're running an H bridge driver, you will have two outputs, one for forward, one for reverse
if (Forward){
   analogWrite(ReverseOutputPin,0);//make sure you don't drive in both directions at once!
   analogWrite(ForwardOuputPin, motorSpeed);
}
else{
   analogWrite(ForwardOutputPin,0);
   analogWrite(ReverseOutputPin,motorSpeed);
}

Perhaps this isn't what you're looking for, perhaps you can just use some bits and pieces of it..

did this

(sensorValue < where - 1)

all it did was stop 1 before then hunt to when it got father away :confused:

if(sensorValue > where)
{
if (sensorValue - where > 10)
{
motorSpeed = 255;
}
if (sensorValue - where < 10)
{
motorSpeed = 127;
}
if (sensorValue - where < 3)
{
motorSpeed = 64;
}
}

was the 10 in the middle meant to be something like 5?
but would this stop the hunting tho?

tammytam:
Maybe something along these lines:

// keep both sensorValue and where in range of 0 to 1023, get the delta then shift down by 2, which

// effectively divides by 4 (more importantly takes your 0-1023 range into 0-255 that the PWM takes

int motorSpeed = ( sensorValue - where ) >> 2;
analogWrite(vent1PWMB ,motorSpeed);

i don't understand this if I'm honest, could we be a bit more in-depth?

Here's how I'd do it.. I don't quite understand some of the code, but here's how I'd control the motor smoothly with a deadband where it doesn't move, so that it follows what you're doing on the pot.. that is what you're trying to accomplish right?

yes :slight_smile:

have you used this? as looking at the bit below wouldn't the motor just move one way then the other continuously or at i over looking something?

if (Forward){
analogWrite(ReverseOutputPin,0);//make sure you don't drive in both directions at once!
analogWrite(ForwardOuputPin, motorSpeed);
}
else{
analogWrite(ForwardOutputPin,0);
analogWrite(ReverseOutputPin,motorSpeed);
}

thanks you all for your input :slight_smile:

If the motor is connected to some sort of pot that it's moving, then no, as the motor moves, the pot value will change, slowing the motor down.. the deadband will prevent it from overshooting... Of course if your motor polarity is backward it'll go the wrong way.

In the code you copied that I posted, you need to know which way to turn, but the amplitude is determined before that in motorSpeed...

Does that clarify at all?

Maybe something along these lines:

// keep both sensorValue and where in range of 0 to 1023, get the delta then shift down by 2, which

// effectively divides by 4 (more importantly takes your 0-1023 range into 0-255 that the PWM takes

int motorSpeed = ( controlPot - MotorPot ) >> 2;
motorSpeed = motorSpeed < 5 ? 0 : motorSpeed; // NEW LINE, should remove hunting
analogWrite(vent1PWMB ,motorSpeed);




i don't understand this if I'm honest, could we be a bit more in-depth?

I've renamed the variables from yours to the same names Rx7man uses.

It should increase the motor speed relative the the difference, larger difference means faster motorspeed. All the >> (shift operator) is doing, is dividing the 0-1024 ranges into 0-255 ranges (effectively like what the map function would do)

There is still a chance it will hunt though, even if that's at very very low speeds, I've added an extra line that should get rid of that. In the new line, if they are within 5 of each other, it will not turn the motor (5 is tweakable, and is roughly 2% deadband)

Code for controlling servos using pots that includes a dead band feature to account for pot noise.

//zoomkat dual pot/servo test 12-29-12
//view output using the serial monitor

#include <Servo.h> 
Servo myservoS1;
Servo myservoS2;

int potpinS1 = 0;  //analog input pin A0
int potpinS2 = 1;

int newvalS1, oldvalS1;
int newvalS2, oldvalS2;

void setup() 
{
  Serial.begin(9600);  
  myservoS1.attach(2);  
  myservoS2.attach(3);
  Serial.println("testing dual pot servo");  
}

void loop() 
{ 
  newvalS1 = analogRead(potpinS1);           
  newvalS1 = map(newvalS1, 0, 1023, 0, 179); 
  if (newvalS1 < (oldvalS1-2) || newvalS1 > (oldvalS1+2)){  
    myservoS1.write(newvalS1);
    Serial.print("1- ");
    Serial.println(newvalS1);
    oldvalS1=newvalS1;
  }

  newvalS2 = analogRead(potpinS2);
  newvalS2 = map(newvalS2, 0, 1023, 0, 179);
  if (newvalS2 < (oldvalS2-2) || newvalS2 > (oldvalS2+2)){  
    myservoS2.write(newvalS2);
    Serial.print("2- ");    
    Serial.println(newvalS2);
    oldvalS2=newvalS2;
  }
  delay(50); //slow down looping to better read serial monitor 
}

TammyTam, I was wondering what the easiest way to implement that was... I hadn't lost any sleep over it, but that works rather nicely... though if you have a deadband where the motor doesn't move anyhow, you shouldn't need it.. What it can do is ensure that you apply enough power to the motor to actually move it and not just sit there and make heat.

Something to keep in mind too is that particularly if you have a slow ramp rate, it will drastically increase the effective deadband

right i have had a play with your example and mingle some of my bits in as i have to look at the limits and enable for the H-bridge as well.
let me no what you think and if i am going the right way?
tammytam:

// keep both sensorValue and where in range of 0 to 1023, get the delta then shift down by 2, which
// effectively divides by 4 (more importantly takes your 0-1023 range into 0-255 that the PWM takes

int motorSpeed = ( controlPot - MotorPot ) >> 2;
motorSpeed = motorSpeed < 5 ? 0 : motorSpeed; // NEW LINE, should remove hunting

// one way
if (digitalRead(vent1UPlim)== HIGH) {
analogWrite(vent1PWMB , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMA ,motorSpeed);
mydisp.drawStr(0, 2, "-close-|");
} else {
analogWrite(vent1PWMA , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}

// other way
if (digitalRead(vent1DOWNlim)== HIGH) {
analogWrite(vent1PWMA , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMB ,motorSpeed);
mydisp.drawStr(0, 2, "-open -|");
} else {
analogWrite(vent1PWMB , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}

// disabled drivers when not being used
if (motorSpeed > 5) {
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}

Rx7man:

int MaxSpeed = 255; //The maximum speed you want to run at.. perhaps you want to not run at full speed.. values are from 0-255;
int FullSpeedPotDifference = 100; //when the values are more than this apart, you will be running at MaxSpeed
//The motor will linearly slow down from there to the deadband point, where it will stop

int Deadband = 3; //No motor output if the pots are within this value of each other
int motorPot = analogRead(InputPin1); //the pot your motor is mechanically controlled to
int controlPot = analogRead(InputPin2); //the 0-10V input
int potDifference = controlPot-motorPot;

boolean Forward = potDifference >=0;

int motorSpeed = map(abs(potDifference),Deadband,FullSpeedPotDifference,0,MaxSpeed);

motorSpeed = constrain(motorSpeed,0,MaxSpeed); //We need to constrain it to our limits now

//if you're running an H bridge driver, you will have two outputs, one for forward, one for reverse
if (Forward){
analogWrite(ReverseOutputPin,0);//make sure you don't drive in both directions at once!
analogWrite(ForwardOuputPin, motorSpeed);
}
else{
analogWrite(ForwardOutputPin,0);
analogWrite(ReverseOutputPin,motorSpeed);
}

// one way
if (Forward){
if (digitalRead(vent1UPlim)== HIGH) {
analogWrite(vent1PWMB , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMA ,motorSpeed);
mydisp.drawStr(0, 2, "-close-|");
} else {
analogWrite(vent1PWMA , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}

} else {

// other way
if (digitalRead(vent1DOWNlim)== HIGH) {
analogWrite(vent1PWMA , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMB ,motorSpeed);
mydisp.drawStr(0, 2, "-open -|");
} else {
analogWrite(vent1PWMB , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}
}

// disabled drivers when not being used
if (motorSpeed > 100) { // 100 being the min speed?
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");

zoomkat:

zoomkat:
Code for controlling servos using pots that includes a dead band feature to account for pot noise.

//zoomkat dual pot/servo test 12-29-12

//view output using the serial monitor

#include <Servo.h>
Servo myservoS1;
Servo myservoS2;

int potpinS1 = 0;  //analog input pin A0
int potpinS2 = 1;

int newvalS1, oldvalS1;
int newvalS2, oldvalS2;

void setup()
{
  Serial.begin(9600); 
  myservoS1.attach(2); 
  myservoS2.attach(3);
  Serial.println("testing dual pot servo"); 
}

void loop()
{
  newvalS1 = analogRead(potpinS1);         
  newvalS1 = map(newvalS1, 0, 1023, 0, 179);
  if (newvalS1 < (oldvalS1-2) || newvalS1 > (oldvalS1+2)){ 
    myservoS1.write(newvalS1);
    Serial.print("1- ");
    Serial.println(newvalS1);
    oldvalS1=newvalS1;
  }

newvalS2 = analogRead(potpinS2);
  newvalS2 = map(newvalS2, 0, 1023, 0, 179);
  if (newvalS2 < (oldvalS2-2) || newvalS2 > (oldvalS2+2)){ 
    myservoS2.write(newvalS2);
    Serial.print("2- ");   
    Serial.println(newvalS2);
    oldvalS2=newvalS2;
  }
  delay(50); //slow down looping to better read serial monitor
}

this look a easy way to do this but does this still have speed control? and i could add my 0-10v into that was well?

thanks again :slight_smile:

So now you have 3 methods, did you try them? Let us know the results.

well not very good tammytam one executes of the code so just flashes everything on and off and Rx7man one looking like this now:

int MaxSpeed = 255; //The maximum speed you want to run at.. perhaps you want to not run at full speed.. values are from 0-255;
int FullSpeedPotDifference = 100; //when the values are more than this apart, you will be running at MaxSpeed
//The motor will linearly slow down from there to the deadband point, where it will stop
int Deadband = 3; //No motor output if the pots are within this value of each other
int potDifference = 0;

void loop() {

boolean Forward = potDifference >=0;
boolean Reverse = potDifference <=0;
int potDifference = where-sensorValue;

int motorSpeed = map(abs(potDifference),Deadband,FullSpeedPotDifference,0,MaxSpeed);

motorSpeed = constrain(motorSpeed,0,MaxSpeed); //We need to constrain it to our limits now

// one way
if (Forward){
if (digitalRead(vent1UPlim)== HIGH) {
analogWrite(vent1PWMB , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMA ,motorSpeed);
mydisp.drawStr(0, 2, "-close-|");
} else {
analogWrite(vent1PWMA , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}

}

// other way
if (Reverse){
if (digitalRead(vent1DOWNlim)== HIGH) {
analogWrite(vent1PWMA , 0 );
digitalWrite(vent1enable, HIGH);
delay(50);
analogWrite(vent1PWMB ,motorSpeed);
mydisp.drawStr(0, 2, "-open -|");
} else {
analogWrite(vent1PWMB , 0 );
delay(50);
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}
}

// disabled drivers when not being used
if (motorSpeed > 100) { // 100 being the min speed?
digitalWrite(vent1enable, LOW);
mydisp.drawStr(0, 2, " |");
}
}

just don't get any output so i don't no if i have dun something wrong on the speed side?

and can we use the servo library for what i would like to do?