Go Down

Topic: Unexpected intereference (Read 399 times) previous topic - next topic

bavareze

Nov 28, 2020, 05:07 am Last Edit: Nov 28, 2020, 05:13 am by bavareze
Hello.

This is a simple project.  I am using a stepper motor attached to a slider mechanism, with two switches (to detect end of scale), a potentiometer to control movement and the steppter motor driver A4988.

At the beginning I had no micro switches.  Instead I used 2 push buttons on the bread board.  Pressing them would cause an event called "Hit Left Limit" and "Hit Right Limit" to calibrate the slider.

Now after I glued microswitches to the slider and ran 3 wires to it (red oval), I can see the 2 Limit events being triggered randomly, without the microswitches being activated.  I tried to use pull up 10kohm resistors (white oval) but did not improve.

I am suspecting the 4 motor wires (green oval) are causing some sort of electricity being induced in the sensor wires.  How can I avoid this?

Thanks






Wawa

#1
Nov 28, 2020, 07:36 am Last Edit: Nov 28, 2020, 08:05 am by Wawa
Limit switches should be normally closed, and open when activated.
The switch should be between pin and ground, with pull up enabled in pinMode.
Switch/ground wire should be twisted pair, to reduce motor interference pickup.

Did you use potentially problematic interrupts (pin 2,3), or just polling.
Leo..

MarkT

Try 1k pullup, not 10k, so its much more robust to interference, and yes, definitely use
twisted pair (and possibly shield) to protect those switch signals. 

Loose separate wires act as a loop antenna picking up all manner of EMI.  Its easy to
make up twisted pair using a cordless screwdriver/drill on slow speed, or with a hand
drill.

If you use a shielded cable the shield should only be connected to ground at one end
and not be part of the sensor circuit.
[ I DO NOT respond to personal messages, I WILL delete them unread, use the forum please ]

bavareze

Limit switches should be normally closed, and open when activated.
The switch should be between pin and ground, with pull up enabled in pinMode.
Switch/ground wire should be twisted pair, to reduce motor interference pickup.

Did you use potentially problematic interrupts (pin 2,3), or just polling.
Leo..
Why normally closed?  Does that have to do with interference? I have them normally open (but I could reconfigure), with pinMode configured as pull up.  And then I assigned interrupt handlers on event FALLING, with FALLING occurring when switch closes the circuit to the ground.  Is this wrong?
And I used int for switch but polling for the potentiometer.
I only have 1 common ground for both switches.  Is that bad too?


bavareze

Try 1k pullup, not 10k, so its much more robust to interference, and yes, definitely use
twisted pair (and possibly shield) to protect those switch signals.  

Loose separate wires act as a loop antenna picking up all manner of EMI.  Its easy to
make up twisted pair using a cordless screwdriver/drill on slow speed, or with a hand
drill.

If you use a shielded cable the shield should only be connected to ground at one end
and not be part of the sensor circuit.
I switched to 1k and now it works if I hold the wires separated by hand.  Next step is to twist.  Since it is 3 of them (1 gnd and 2 switches) can they be all together or must be 2 separate pairs?

jremington

#5
Nov 29, 2020, 03:09 am Last Edit: Nov 29, 2020, 03:10 am by jremington
Breadboards are for low power logic circuitry and the contacts tend to burn if subjected to motor currents. I strongly advise soldering motor and power connections, or use secure screw terminals if available.

Incidentally, if a motor connection becomes loose or is manually disconnected while the system is powered up, the driver will be instantly destroyed. Burned breadboard tracks lead to this sort of disaster.

bavareze

On the first attempt at twisting wires with the Dremel 3000, the tool started too fast, pulled all the wires from the board and started whipping me like crazy.

I took notice and I started the process again slower and this time I made this wonderful twisted pair and a half (3 wires) that works flawlessly!

Thanks

(it is still with 1k pull up and switches normally open.  Is that 1k gonna be ok long run or could cause some difficulties due to current draw?)






Wawa

An opening contact is more reliable than a (old/dirty) closing contact.
And a signal wire of a twisted pair that is normally grounded is less likely to pick up interference.

Interrupts is for fast re-occurring things, like rotary encoders.
Not needed for a slow end stop, and usually the last thing you should think off.
Polling each loop (between each step of the motor) is just fine, and likely less problematic.
Leo..

Southpark

On the first attempt at twisting wires with the Dremel 3000, the tool started too fast, pulled all the wires from the board and started whipping me like crazy.
Good to see that you're ok. Just got to be careful when it comes to 'power' tools. Eg. gloves, eye-protection etc. It's crazy unforeseen things like that which can make what should have been a good normal day turn into a bad day - unnecessarily.

TomGeorge

Hi,
If you keep getting interference on your limit switch wires, it may be worth trying to wire the limit switches as change over switches, the NC and NO terminals would then be connected directly to gnd and 5V respsectively.
Also a 0.1uF capacitor between the signal wire and gnd is worth a try.
Keep your motor wires well away form the other wiring.
How are you powering the motor?
How are you powering the UNO?

A schematic of your project will help, a circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Hand drawn can be the easiest to do, please include your power supplies and your motor.


Thanks.. Tom... :)
Everything runs on smoke, let the smoke out, it stops running....

Grumpy_Mike

Quote
Is that 1k gonna be ok long run or could cause some difficulties due to current draw?
Yes it is fine in the long run. But do change it over to a normally closed.

AJLElectronics

You should NOT be using interrupts for polling limit switches.

TomGeorge

Hi,
Can you post your code please?
Can you post a schematic?

Thanks.. Tom... :)
Everything runs on smoke, let the smoke out, it stops running....

bavareze

An opening contact is more reliable than a (old/dirty) closing contact.
And a signal wire of a twisted pair that is normally grounded is less likely to pick up interference.

Interrupts is for fast re-occurring things, like rotary encoders.
Not needed for a slow end stop, and usually the last thing you should think off.
Polling each loop (between each step of the motor) is just fine, and likely less problematic.
Leo..

I figured checking a boolean value is less time consuming that a digitalRead() call.  I could switch to polling inbetween motor steps though later on.

bavareze

#14
Nov 30, 2020, 03:03 am Last Edit: Nov 30, 2020, 03:06 am by bavareze
Time for code review:

Main:

Code: [Select]
//#define _VERBOSE_P


#include "stepper.h"
#include "pot.h"

const int calibrateReq =5;

const int MODE_STANDBY=0;
const int MODE_CALIBRATE=1;
const int MODE_RUN=2;
int mode=MODE_STANDBY;


void setup() {
  Serial.begin(9600);
  Serial.println("Starting Asnyc");
  
  pinMode(stepPin,OUTPUT);
  pinMode(dirPin,OUTPUT);
  pinMode(LlimitPin,INPUT_PULLUP);
  pinMode(RlimitPin,INPUT_PULLUP);
  pinMode(calibrateReq,INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(LlimitPin), hitLeftLimit, FALLING);
  attachInterrupt(digitalPinToInterrupt(RlimitPin), hitRightLimit, FALLING);
}



void loop() {
  if(digitalRead(calibrateReq)==LOW)
  {
      mode=MODE_CALIBRATE;
        Serial.println("calibrate req");
  }
  switch (mode) {
    case MODE_STANDBY:    // your hand is on the sensor
      //Serial.println("dark");
      break;
    case MODE_CALIBRATE:    // your hand is close to the sensor
        Serial.println("calibrating");
        calibrate();
        delay(500);
        mode=MODE_RUN;  
      break;
    case MODE_RUN:    // your hand is a few inches from the sensor
#ifdef  _VERBOSE_1
        Serial.println("mode run");
#endif        
      if(readPot())
        {
          long desiredStep = (sensorValue*totalSteps)/1024;
#ifdef  _VERBOSE_1
        String a="total Steps = ";  a+=totalSteps;  a+=" sensorValue=";  a+=sensorValue;  a+=" going to step ";  a+=desiredStep;  a+=" now at step ";  a+=currentStep;  Serial.println(a);          //stepp();
#endif
          goToStep(desiredStep);
        }
        stepp();  // let the stepper routine do it's cycle
      break;
  }

    delayMicroseconds(50);//was 50
}


/*void clearedLeftLimit() {
  leftLimit=LOW;
}

void clearedRightLimit() {
  rightLimit=LOW;
}*/


Stepper.h
Code: [Select]
const int LlimitPin = 2;
const int RlimitPin = 3;
const int stepPin = 6; // define pin for step
const int dirPin = 7;  // define pin for direction


const int minDelay=120;  //120 for single scre
const int maxDelay=700;  //700 for single scre

short acceleration=4;    //3 for single screw
volatile bool hitLeft=false;
volatile bool hitRight=false;

bool waitingMotorSync=false;
bool moving=false;
bool currentDirection=LOW;

long waitingSince;

int stepsToWait=0;
int stepsDone=0;
int currentStep;
int stepsToDo;
int totalSteps=0;
int stepDelay=maxDelay;



void stopp()
{
  if(moving)
  {
    stepsToDo=0;
    /*String a="I did so many steps ";
    a+=stepsDone;
    Serial.println(a);
    stepsDone=0;*/
    waitingMotorSync=false;
    moving=false;  
    stepDelay=maxDelay;
  }
}



void setDirection(bool newDirection)
{
  //stepDelay=maxDelay;  // should not be needed
  if(newDirection!=currentDirection)  //direction change
  {
    currentDirection=newDirection;
    stepDelay=maxDelay;
    if(moving)
    {
      stopp();
//      stepDelay*=1.4;// was 1.2 for single screw; take it easier if sudden change of direction
      stepsToWait=40;
      Serial.println("sudden change of direction");
    }
  }
  digitalWrite(dirPin,currentDirection);
}



void hitLeftLimit() {  //interrupt handler
#ifdef _VERBOSE_5
  Serial.println("hit L");
#endif
  if(moving)
     currentStep=0;
  stopp();
  hitLeft=true;
}

void hitRightLimit() {  //interrupt handler
#ifdef _VERBOSE_5
  Serial.println("hit R");
#endif
  if(moving)
     currentStep=totalSteps;
  stopp();
  hitRight=true;
}


void stepp()
{
/*  if(stepsDone>7000)
    return;*/
  if(!moving)
    return;
  if(stepsToDo<=0)
  {  
    stopp();
    return;
  }
  if(waitingMotorSync)  //stepPin is in LOW, we need to give it at least stepDelay time to execute and sync
  {
    if(micros()>waitingSince+stepDelay*1.5)
      waitingMotorSync=false;
  }
  else
  {
    if(stepsToWait>0)
    {
      stepsToWait--;
//      Serial.println("waiting");
      waitingMotorSync=true;
      waitingSince=micros();
    }
    else
    {
      digitalWrite(stepPin,HIGH);
      delayMicroseconds(stepDelay*0.1);
      digitalWrite(stepPin,LOW);
      waitingMotorSync=true;
      waitingSince=micros();
      stepsToDo--;
      stepsDone++;
      if(currentDirection)
        currentStep++;
      else
        currentStep--;
      if(stepDelay>minDelay)
        stepDelay-=acceleration;
    }
  }
}

void stepLsync()
{
    //Serial.println("stepL called");

  digitalWrite(dirPin, LOW);
  digitalWrite(stepPin,HIGH);
  delayMicroseconds(stepDelay*0.1); //was 500
  digitalWrite(stepPin,LOW);
  delayMicroseconds(stepDelay*1.6); //was 500
/*  if(digitalRead(RlimitPin)==HIGH)
    rightLimit=LOW;*/
}


void stepRsync()
{
  digitalWrite(dirPin, HIGH);
  digitalWrite(stepPin,HIGH);
  delayMicroseconds(stepDelay*0.1); //was 500
  digitalWrite(stepPin,LOW);
  delayMicroseconds(stepDelay*1.6); //was 500
  /*if(digitalRead(LlimitPin)==HIGH)
    leftLimit=LOW;*/
}


void calibrate()  //TODO: calibrate has a bug and can not start if the high limit is already hit
{
    hitLeft=false;
    hitRight=false;
    totalSteps=0;
#ifdef _VERBOSE_5
    Serial.println("CAL  ");
#endif  
     while(!hitRight)
        stepRsync();

#ifdef _VERBOSE_5
    Serial.println("CAL 2 ");
#endif  
     delay(500);
     while(!hitLeft)
     {
      stepLsync();
      totalSteps++;
     }
#ifdef _VERBOSE_5
     String a="total steps= ";
     a+=totalSteps;
  Serial.println(a);
#endif  
/*  for(int i=0; i<totalSteps/2; i++)
    stepL();*/
    currentStep=0;
}


void goLeft(int numSteps)
{
#ifdef _VERBOSE_1
  String a="Go left ";
  a+=numSteps;
  Serial.println(a);
#endif  
    setDirection(false);
    stepsToDo=numSteps;
    moving=true;
}

void goRight(int numSteps)
{
#ifdef _VERBOSE_1
  String a="Go right ";
  a+=numSteps;
  Serial.println(a);
#endif  
    setDirection(true);
    stepsToDo=numSteps;
    moving=true;
}


void goToStep(int destination)
{
  if(abs(destination-currentStep)<100)//ignore less than half turn requests
  {
#ifdef _VERBOSE_1
     String a="Waiting at step "; a+=currentStep; Serial.println(a);
#endif
  }
  else
  {
    if(destination<currentStep)
    {
#ifdef _VERBOSE_3
      Serial.println("go left");
#endif
       setDirection(false);
    }
    else
    {
#ifdef _VERBOSE_3
      Serial.println("go Right");
#endif      
      setDirection(true);
    }
    stepsToDo=abs(currentStep-destination);
    moving=true;
#ifdef _VERBOSE_1
    String a="I am at step "; a+=currentStep; a+=" need to go to "; a+=destination;  Serial.println(a);
#endif    
  }
}




Go Up