How I reduce vibration when tracking

vogl

New member
Hi,

after successful testing perimeter I try track mower to base station. Mower goes to wire and then track it. But big vibration (to left and right over perimeter axis) is my problem. I look to videos on youtube, there no vibration, mowers track smoothly. How I reduce it ? Via parameters of PID or other constants ?

Thank you
 
Hi
If you use ardumower chassis you need to adjust pid in perimeter setting and pwm max value in motor setting to slow down the tracking.
But you need to remember that the coil need to be in and out the perimeter during the transitiontimeout of the perimeter setting to avoid a total stop of one of the two wheels
Sorry for my English
By
 
Thank you for reply. I study PID regulator and try to modify params. I have still problem with oscilation.
I expect that after modify params both wheels rotate (with different speed based on computin PID), but in all situation and params only ONE wheel rotate.
When I modify integral Ki constant (or Kp), robot change amplitude, but insufficiently to use with base station docking. Still only one wheel rotate in half period.
Why ?

I have pwm about 150. Rpm is about 30.
Kp=50, Ki=26, Kd=5

I use software version 1.0a6
 
Hi.
If only one Wheel rotate it s not normal.
Normally the mower need to oscillate in and out of the perimeter with the 2 wheel rotate alternatively at different speed (depending of pid value).If the mower stay in or out for more than 2500 ms (transition timeout in setting perimeter) then one wheel completely stop so the mower find the wire again.

So please put the timeout at 6000ms for example.
Try with pwm motor very low 100 for example.
Put the D value in perimeter setting to 0.
And verify that you have the 2 wheels rotate at the same for at list 6000 ms.
If it is ok you can put the timeout again to 2000 ms and try to adapt the pid and pwm.
The pwm value need also to be according with rpm value .
Hope it can help.
By.
 
Thanks all for reply.

I try test with "block inner wheel off", try maximize transition timeout.

With high transition timeout robot stilll osillate
wheel left +, wheel right stop
delay 0,5sec,
wheel left stop, wheel right+

With low transition timeout robot
wheel left +, wheel right -
delay about 0,2sec,
wheel left -, wheel right+

I mean, that robot has still this condition true

Code:
if ((millis() > stateStartTime + 5000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut))

and never activate PID regulator.
 
Hi.
I mean, that robot has still this condition true
I tell you to test with the transition timeout at 5000ms to be sure this condition is not true.
So for me if like you say the 2 wheels don't rotate at the same time please verify the PerimeterMag value to be sure the perimetertransition work.

Maybe you can try to reduce the speed of motor PWM (not RPM) and test with transitiontimeout=5000.
And try PID low like P=16 I=4 D=0

By
 
Both wheel start rotate after I set parameter "Timed-out if below smag" greater. I set it to 0 before, because when timeout is greater than 0 robot after some seconds stop working with perimeter timeout error.
 
Hi.
Timed-out if below smg is totaly different than transition timeout.
So hope all is ok now ?
 
Hi, today I do factory reset, recalibre perimeter and measure SNR. After this and P=20 I=4 D=0 robot track perimeter. Oscilation sometimes apear, but tracking is better. Wheels both rotate.
Can you explain me how to get the best parameters of PID regulator ?

Thank you
 
Hi.
It's not easy to find a perfect PID for tracking only test is the solution but if you use ardumower chassis and motor etc...,normaly the defaut setting are OK.
You can find help on PID in the wiki but it's also depend of your working area.
For example in a circle area you can set the transition timeout at a high value and use a soft PID,but in square you need a small transition timeout and a fast PID.
All depend of the position and the max angle in the wire.
Good luck.
 
Hi,
I think I have same problem like a lot of users with perimeter tracking.
First I posting videos:

Orgiginal factory setup (PWM max255 and RPMmax30) : https://1drv.ms/v/s!AgsZm2jRj35YjDyRS_4MItF2zSWF
Original factory setup (PWM max100 and RPMMax30): https://1drv.ms/v/s!AgsZm2jRj35YjD3gwvlUmCwLbynI
But to uderstand my problem, I need information which all parameters I can setup - there is a PID parameters, any timeouts, roll times and I'm not sure what all has a influence on perimeter tracking.

But reduce max PWM isn't good solution, because tracking is too slow and also speed during mowing is decreased.

Alex
 
Let's do it in this way :


Code:
// PID controller: track perimeter 
void Robot::motorControlPerimeter(){    
  if (millis() < nextTimeMotorPerimeterControl) return;
    nextTimeMotorPerimeterControl = millis() + 100;
  if ((millis() > stateStartTime + 5000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)){
    // robot is wheel-spinning while tracking => roll to get ground again
    if (trackingBlockInnerWheelWhilePerimeterStruggling == 0){
    if (perimeterInside) setMotorPWM( -motorSpeedMaxPwm/1.5, motorSpeedMaxPwm/1.5, false);
        else setMotorPWM( motorSpeedMaxPwm/1.5, -motorSpeedMaxPwm/1.5, false);}
    else if (trackingBlockInnerWheelWhilePerimeterStruggling == 1){
      if (perimeterInside) setMotorPWM( 0, motorSpeedMaxPwm/1.5, false);
        else setMotorPWM( motorSpeedMaxPwm/1.5, 0, false);
    }
    if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut){      
      Console.println("Error: tracking error");
      addErrorCounter(ERR_TRACKING);
      //setNextState(STATE_ERROR,0);
      setNextState(STATE_PERI_FIND,0);
    }
    return;
  }   
  if (perimeterInside)
      perimeterPID.x = -1;
    else
      perimeterPID.x = 1;
  perimeterPID.w = 0;
  perimeterPID.y_min = -motorSpeedMaxPwm;
  perimeterPID.y_max = motorSpeedMaxPwm;		
  perimeterPID.max_output = motorSpeedMaxPwm;
  perimeterPID.compute();
  //setMotorPWM( motorLeftPWMCurr  +perimeterPID.y, 
  //               motorRightPWMCurr -perimeterPID.y, false);      
  setMotorPWM( max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 - perimeterPID.y)), 
                 max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 + perimeterPID.y)), false);      
  /*Console.print(perimeterPID.x);
  Console.print("t");          
  Console.println(perimeterPID.y);  */
}


Please correct me :


Code:
if ((millis() > stateStartTime + 5000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)){
    // robot is wheel-spinning while tracking => roll to get ground again
    if (trackingBlockInnerWheelWhilePerimeterStruggling == 0){
    if (perimeterInside) setMotorPWM( -motorSpeedMaxPwm/1.5, motorSpeedMaxPwm/1.5, false);
        else setMotorPWM( motorSpeedMaxPwm/1.5, -motorSpeedMaxPwm/1.5, false);}
    else if (trackingBlockInnerWheelWhilePerimeterStruggling == 1){
      if (perimeterInside) setMotorPWM( 0, motorSpeedMaxPwm/1.5, false);
        else setMotorPWM( motorSpeedMaxPwm/1.5, 0, false);
    }


not sure where from all information comes :

if ((millis() > stateStartTime + 5000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)){

I know that "trackingPerimeterTransitionTimeOut" I can set and default is 2500. But "perimeterLastTransitionTime" and "stateStartTime " isn't clear for me.

Then I see that depends on "trackingBlockInnerWheelWhilePerimeterStruggling" (also is possible set on/off) mower will start turning one or both wheels.

On the end I see :


Code:
if (perimeterInside)
      perimeterPID.x = -1;
    else
      perimeterPID.x = 1;
  perimeterPID.w = 0;
  perimeterPID.y_min = -motorSpeedMaxPwm;
  perimeterPID.y_max = motorSpeedMaxPwm;		
  perimeterPID.max_output = motorSpeedMaxPwm;
  perimeterPID.compute();
  //setMotorPWM( motorLeftPWMCurr  +perimeterPID.y, 
  //               motorRightPWMCurr -perimeterPID.y, false);      
  setMotorPWM( max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 - perimeterPID.y)), 
                 max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 + perimeterPID.y)), false);      
  /*Console.print(perimeterPID.x);
  Console.print("t");          
  Console.println(perimeterPID.y);  */


For me it looks like a wheels PID regulation depends on position inside/outside.

What isn't clear for me, if my mower (see video in my previous post) is running according first code or according PID code.

What is also not clear for me, when I set maxPWM to 100, that mower goes slowly all the time (not only during perimeter tracking). Odometry is on and RPM set to 30.

Alex
 
Hello.
Roland is right it's motorControlPerimeter() who controls the tracking.
The problem is the algorithme that manages the monitoring
It is ruled by these lines

Code:
if (perimeterInside)
      perimeterPID.x = -1;
    else
      perimeterPID.x = 1;

which requires to do an in and out in less time than the perimetertimeout otherwise one of the two wheels is blocked (what you see on your video.

2 Solutions for example if the timeout is 2500ms.
1 Find a Pid that allows the mower to oscillate between in and out in less than 2500ms (Personally I did not succeed but I have a Denna platform and the coil receiving the loop signal is very far ahead The axis of the wheels of the mower , which increases the jerks)
2 Completely change this part of the code (What I did and which works a little better but was not very fast to my taste with the Mega that is why I am switching to a DUE)

The problem is that I have modified a lot of things in Azurit and now my code works only for an Arduino DUE and a mandatory Odometry and never tested in ardumower platform.
However I think it is possible if you have programming knowledge to reintegrate the parties that interest you.

Below is the part of the motorControlPerimeter() where you will see that the algorithm is slightly different.
I use the PerimeterMag as cible to smooth the tracking instead of -1 and 1
Warning replace 15 by 30 in 15; //bb read the perimeter each 15ms not possible with the MEGA maxi 30ms



Code:
// PID controller: track perimeter
void Robot::motorControlPerimeter() {
  if (millis() < nextTimeMotorPerimeterControl) return;
  nextTimeMotorPerimeterControl = millis() + 15; //bb read the perimeter each 15ms not possible with the MEGA maxi 30ms 
  //never stop the PID compute while turning for the new transition
  //use the PerimeterMag as cible to smooth the tracking
  //Value reference perimeterMagMaxValue , maybe need to be calculate in mower setting up procedure

  perimeterPID.x = double(perimeterMag) / perimeterMagMaxValue; // PID is compute between 1 and -1
  //if (perimeterPID.x > 1 ) perimeterPID.x = 1;
  //if (perimeterPID.x < -1 ) perimeterPID.x = -1;
  perimeterPID.w = 0;
  perimeterPID.y_min = -MaxSpeedperiPwm;
  perimeterPID.y_max = MaxSpeedperiPwm;
  perimeterPID.max_output = MaxSpeedperiPwm;
  perimeterPID.compute();
  perimeterPID.y = 2.5 * perimeterPID.y;


  if ((millis() > stateStartTime + 10000) && (millis() > perimeterLastTransitionTime + trackingPerimeterTransitionTimeOut)) {
    // robot is wheel-spinning while tracking => roll to get ground again

    if (trackingBlockInnerWheelWhilePerimeterStruggling == 0) {
      if (perimeterInside) {
        rightSpeedperi = max(-MaxSpeedperiPwm, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2  + perimeterPID.y));
        leftSpeedperi = -MaxSpeedperiPwm / 2;
      }
      else {
        rightSpeedperi = -MaxSpeedperiPwm / 2;
        leftSpeedperi = max(-MaxSpeedperiPwm, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2 - perimeterPID.y));
      }
    }
    if (trackingBlockInnerWheelWhilePerimeterStruggling == 1) {
      if (perimeterInside) {
        rightSpeedperi = max(-MaxSpeedperiPwm, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2  + perimeterPID.y));
        leftSpeedperi = 0;
      }
      else {
        rightSpeedperi = 0;
        leftSpeedperi = max(-MaxSpeedperiPwm, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2 - perimeterPID.y));
      }
    }
    if (consoleMode == CONSOLE_TRACKING) {
      Console.print("Perte  du  fil ; ");
      Console.print(millis());
      Console.print("; MAG: ;");
      Console.print (perimeterMag);
      Console.print("; ;");
      Console.print(perimeterInside);
      Console.print("; Speed: L/R ;");
      Console.print (leftSpeedperi);
      Console.print(";");
      Console.print (rightSpeedperi);
      Console.print("; PerimeterPID.x: ;");
      Console.print (perimeterPID.x);
      Console.print("; PerimeterPID.y: ;");
      Console.print(perimeterPID.y);
      Console.print("; perimeterLastTransitionTime: ;");
      Console.println(perimeterLastTransitionTime);
    }
    setMotorPWM( leftSpeedperi, rightSpeedperi, false);

    lastTimeForgetWire = millis();

    if (millis() > perimeterLastTransitionTime + trackingErrorTimeOut) {
      Console.println("Error: tracking error");
      addErrorCounter(ERR_TRACKING);
      //setNextState(STATE_ERROR,0);
      setNextState(STATE_PERI_FIND, 0);
    }
    return;
  }

    if ((millis() - lastTimeForgetWire ) < trackingPerimeterTransitionTimeOut / 2 ) {

    rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2 +  perimeterPID.y / 2));
    leftSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2 -  perimeterPID.y / 2));
    if (consoleMode == CONSOLE_TRACKING) {
      Console.print("retour lent sur fil ; ");
    }
  }
  else
  {
    rightSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2  + perimeterPID.y));
    leftSpeedperi = max(0, min(MaxSpeedperiPwm, MaxSpeedperiPwm / 2 - perimeterPID.y));
    if (consoleMode == CONSOLE_TRACKING) {
      Console.print("suivi du fil  ; ");
    }
  }

  setMotorPWM( leftSpeedperi, rightSpeedperi, false);


  //if the mower move in perfect straight line the transition between in and out is longuer so you need to reset the perimeterLastTransitionTime
  //Value of timedOutIfBelowSmag depend on the distance between the coil and the perimeter wire maybe need to be calculate in mower setting up procedure
  //timedOutIfBelowSmag hope it is the value read a the point the more far of the perimeter wire
  // if ((perimeterMag > -300) && (perimeterMag < 300)) {

  if (abs(perimeterMag ) < 300) { //300 can be replace by timedOutIfBelowSmag to be tested
    perimeterLastTransitionTime = millis(); //initialise perimeterLastTransitionTime if perfect sthraith line
  }

  if (consoleMode == CONSOLE_TRACKING) {
    Console.print(millis());
    Console.print("; MAG: ;");
    Console.print (perimeterMag);
    Console.print("; ;");
    Console.print(perimeterInside);
    Console.print("; Speed: L/R ;");
    Console.print (leftSpeedperi);
    Console.print(";");
    Console.print (rightSpeedperi);
    Console.print("; PerimeterPID.x: ;");
    Console.print (perimeterPID.x);
    Console.print("; PerimeterPID.y: ;");
    Console.print(perimeterPID.y);
    Console.print("; perimeterLastTransitionTime: ;");
    Console.println(perimeterLastTransitionTime);
  }
}


Also you need to add a lot of variable in robot.h and mower.cpp and also in Pfod.cpp

in mower.cpp

Code:
trackingPerimeterTransitionTimeOut = 1500;
  trackingErrorTimeOut = 10000;
  trackingBlockInnerWheelWhilePerimeterStruggling = 1;
  //bb
  MaxSpeedperiPwm = 180; // speed max in PWM while perimeter tracking
  RollTimeFor45Deg = 1000; //time while roll in peri obstacle avoid if no Odometry
  circleTimeForObstacle = 4000; //time while arc circle in peri obstacle avoid if no Odometry
  circleDistForObstacle = 150; //distance while arc circle in peri obstacle avoid
  perimeterMagMaxValue = 2000; // Maximum value return when near the perimeter wire (use for tracking and slowing when near wire
//bb
  //offset in PWM use for the 2 wheels motor have the same speed a the same PWM
  //use the 1 ml ODO test to find good value the 2 wheels need to stop at the same time
  motorRightOffset = 0;


In robot.h

Code:
//bb
// console mode
enum { CONSOLE_SENSOR_COUNTERS, CONSOLE_SENSOR_VALUES, CONSOLE_PERIMETER, CONSOLE_OFF ,CONSOLE_TRACKING };
 //add BB
    int leftSpeedperi;
    int rightSpeedperi;
    int lastLeftSpeedperi;
    int lastRightSpeedperi;
    int uu;
    int vv;
    unsigned long lastTimeForgetWire;
    unsigned long NextTimeNormalSpeed;
    int LastPerimeterMag;
    double CiblePeriValue;
    int MaxSpeedperiPwm;
    unsigned long RollTimeFor45Deg;
    unsigned long circleTimeForObstacle;
    int circleDistForObstacle;
    int perimeterMagMaxValue;
    int Tempovar;
    
    //End add bb


For the Pfod i don't remenber the change i made so i put in attachment all the code

BE CARREFUL THAT THIS CODE IS FOR DUE AND I REMOVE ALL CONCERNING THE MEGA.

I am sure i forget a lot of thing to make this code work on your mower but do not hesitate and i try to explain what i forget..
 
Hi,
I don't want go way to make a masive code change.
There must be a other way.
First of all, mower must jump into code where wheels are driven via PID.
So I can increase "trackingPerimeterTransitionTimeOut" to 6000, then PID will control the mower ?
Decision inside outside is done only depends on change value from + to - or from - to + ?

Alex
 
Hi
So
I know that "trackingPerimeterTransitionTimeOut" I can set and default is 2000. But "perimeterLastTransitionTime" and "stateStartTime " isn't clear for me.
perimeterLastTransitionTime is the moment in millis when the mower go from in to out or out to in (The transition).
stateStartTime is the moment in millis when the mower start the tracking (just after the perimeter find).
Trackingblockinnerwheel is not very important for the vibration, You can see the difference in the code
In one case the Wheel is stop in the other it rotate in reverse at half speed.

What isn't clear for me, if my mower (see video in my previous post) is running according first code or according PID code.

Yes it's the Pid you find in Permeter setting and it manage the Wheel on half off the speed

Code:
setMotorPWM( max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 - perimeterPID.y)), 
                 max(-motorSpeedMaxPwm, min(motorSpeedMaxPwm, motorSpeedMaxPwm/2 + perimeterPID.y)), false);


to help the mower go from in to out or inverse in less time than the Perimetertransitiontimeout
And as i say in the precedent post the problem is in

Code:
if (perimeterInside)
      perimeterPID.x = -1;
    else
      perimeterPID.x = 1;


the perimeterPID.x is normaly on a correct PID regulation the the value you have (for example on a Wheel the real speed) and here this value is force to 1 or -1 to make the mower oscilate.
The perimeterPID.w=0 is the cible

What is also not clear for me, when I set maxPWM to 100, that mower goes slowly all the time (not only during perimeter tracking). Odometry is on and RPM set to 30.

Be carreful that in azurit the mower use RPM only in forward mode with odometry.
for all the rest of the movement the maxpwm is use.
If you use Pfod
In setting motor if you set maxpwm to 100 i think you never reach the 30rpm and it's not good.
You need to verify in forward mode that the real pwm if inferior the the maxpwm.
It's why in my code i need to use a specific Perimeter maxpwm.

Hope you can understand my English correctly because all of this is very easy.
 
So I can increase "trackingPerimeterTransitionTimeOut" to 6000, then PID will control the mower ?

Be carreful i tell you to do this only to be sure the TransitionTimeOut is not reach.
Problem is that if you put 6000 the mower risk to forget the wire in 90 deg angle.
 
Ok, what we can see from two videos which I sent ?
It's with default settings, only second video is with changed PWM.
Or how to proceed now to know if mower is driven via "trackingPerimeterTransitionTimeOut" is over code or via "inside/outside" PID code ?
Alex
 
Oben