controlling linear axis failure

Hello everyone,

I am trying to control a ‘Fischertechnik’ linear axis using an Arduino Uno and a Vellemann Motor&Power Shield for my 9V DC motor. The end of the axis is detected by two pushbuttons which prevent the carriage from overshooting. Feedback on the current position comes from an incremental encoder.
My task is to first move the carriage to one end of the axis, turn and then precisely go to 100 mm from this point. I have a picture of my overall control scheme attached.
However, it usually goes to one end, detects the pushbutton then moves in the right direction and then randomly stops before it should. I hear a high pitched tone as it stops so I’m guessing it has something to do with the pwm signal that I am using to control the motor?
The code looks like this: I apologize for the german comments and variables, it’s the way I got the code. I assume that void Regelkreis() is not working properly so I put some english comments into that function as well. I hope you can still deal with it please let me know if you need the entire code in english.

int Motordreh=4;                            //digitaler Pin
int Motorgeschw=5;                           //pwm-pin
int InterruptPin1 =2;                       //Variable Encoder 1 (an digital Pin 2)
int InterruptPin2 =3;                       //Variable Encoder 2 (an digital Pin 3)

volatile int counter;                                //Zählvariable
float t_old;
float t_new;
float w;                                //Drehgeschwindigkeit entspricht 13,7 mm/s
float v =20;

volatile float x_ist = 0;
float schleppfehler;
int Hardend1=6;         //Hardwareendschalter am Motor (Motornah)
int Ende1;
int Hardend2=10;         //Hardwareendschalter weiter weg vom Motor
int Ende2;
int ruckfahrt=1;
int Los=0;
volatile bool pulseflag = 0;

//Hier Einstellen!!!
float x_soll_ende = 50.0;
float kv = 400;

void CountPulse(){
  if(digitalRead(Motordreh)==0){
    x_ist=x_ist+0.063;                                     //nochmal gucken was 0.063 ist bzw wie es zustande kommt
counter++ ;
}
if(digitalRead(Motordreh)==1){
x_ist=x_ist+0.063;
}
pulseflag = 1;
}

void setup() {
 Serial.begin(9600);                                                 //Schnittstelle fur Monitor in Baud
 pinMode(Motordreh,OUTPUT);                                          //Motorpin1 als Ausgang deklariert
 pinMode(Motorgeschw,OUTPUT);                                        //Motorpin2 als Ausgang deklariert
 pinMode(Hardend1, INPUT);
 digitalWrite(Hardend1,HIGH);
 pinMode(Hardend2, INPUT);
 digitalWrite(Hardend2,HIGH);
// pinMode(InterruptPin1,INPUT);                                       //interner Pull-Up Widerstand1 aktiviert
// pinMode(InterruptPin2,INPUT);                                       //interner Pull-Up Widerstand2 aktiviert
 attachInterrupt(digitalPinToInterrupt(2),CountPulse,CHANGE);        //aktiviert den Interrupt an Pin2
 digitalWrite(2,HIGH);                                               //aktivieren des internen Pull-UP Widerstandes
 attachInterrupt(digitalPinToInterrupt(3),CountPulse,CHANGE);        //aktiviert den Interrupt an Pin3
 digitalWrite(3,HIGH); //aktivieren des internen Pull-UP Widerstandes
 
 digitalWrite(Motordreh,0);
analogWrite(Motorgeschw,255);
}


void Lageregelkreis(){               //position control
 float x_soll = 0;

//calculate setpoint
 t_new=millis();
 Serial.print("t_old:     ");
  Serial.println(t_old);
  Serial.print("t_new:     ");
  Serial.println(t_new);


 x_soll =(v*((t_new-t_old)/1000))/2; 
 Serial.print("X-Soll:     ");
 Serial.println(x_soll);

//restrict setpoint
 if(x_soll>=x_soll_ende){
   x_soll= x_soll_ende;
   }

//calculate contouring error
schleppfehler= x_soll- x_ist; 

//calculate motor speed

if(schleppfehler >= 0){       //Motordreh is giving the direction of the motor
digitalWrite(Motordreh,0);
w = schleppfehler*kv;
}
if(schleppfehler < 0){
digitalWrite (Motordreh,1);
w = schleppfehler*kv*(-1);
}

//restrict maximum revs
if(w > 255){
w = 255;
}

//Output when at the end
if(w >= 5){                                                      //Print contouring error
Serial.write("Schleppfehler ");
Serial.println (schleppfehler); 
}
else{                                                          //Print number of rising or falling edges of the                         incremental encoder

Serial.write("Anzahl steigende Flanken ");
Serial.println (counter/2);
}

//set new speed
analogWrite(Motorgeschw,w);
}


void loop() {
  Ende1=digitalRead(Hardend1);
  Ende2=digitalRead(Hardend2);
  Serial.print("Hardend1:      ");
  Serial.println(Ende1);
  Serial.print("Hardend2:      ");
  Serial.println(Ende2); 
  Serial.print("X-Ist:     ");
  Serial.println(x_ist);  


if((Ende2==1) && (ruckfahrt==0)){
  Serial.println("Ende2 = 1 -> fahren");
digitalWrite(Motordreh,0);
analogWrite(Motorgeschw,w);
ruckfahrt=1;
}  
else if ((Ende2==0) && (ruckfahrt ==1)){
  
   t_old=millis();
  while((t_old + 3000) >= millis()){
    Serial.println("Ende2 = 0 -> halten");

  analogWrite(Motorgeschw,0);
  }
  t_old=millis();
  
 Serial.println("Ende2 = 0 -> wieder fahren");
 analogWrite(Motorgeschw, w);
 digitalWrite(Motordreh, 1);
  
  Los=1;
  x_ist = 0;
  schleppfehler = 0;
}

else if ((Ende1==1) && (Los ==1)) {
  Lageregelkreis();
  
  analogWrite(Motorgeschw,w);
  digitalWrite(Motordreh,1);
  Serial.println("Ende1=1 und Los =1");
}

}

Does anyone know why it would stop before reaching the 100mm?
Any help would be great :slight_smile:

control_scheme.PNG

void CountPulse(){
  if(digitalRead(Motordreh)==0){
    x_ist=x_ist+0.063;                                     //nochmal gucken was 0.063 ist bzw wie es zustande kommt
counter++ ;
}
if(digitalRead(Motordreh)==1){
x_ist=x_ist+0.063;
}
pulseflag = 1;
}

Maybe my German isn't up to the job, but why do you bother to read the Motordreh pin?

t_old should not be a float. Use unsigned long instead.

I have to ask, did this ever work?

Excuse me for not answering! I did not understand the Velleman Shield in the right way. The power source an the motor was connected wrongly. In addition some parts of the code weren't right. After changing these things it worked perfectly :slight_smile: