Henry IX: A fully a...
 
Notifications
Clear all

Henry IX: A fully autonomous robot platform

Page 8 / 9

huckOhio
(@huckohio)
Estimable Member
Joined: 2 years ago
Posts: 161
 

LOL...never mind.  I just saw the email. 


ReplyQuote
BrianG
(@briang)
Trusted Member
Joined: 8 months ago
Posts: 70
Topic starter  
Posted by: @huckohio

LOL...never mind.  I just saw the email. 

Good to hear! Let me know if you have any issues, if you have not used github the easiest way to get the code is to download the whole repository as a zip file (then you do not need to install the git client on your computer). 

PXL 20210722 230200303

Thank you!

/Brian


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@briang

Although I understand this was to illustrate the theory of PID,  a robot following a wall would need to know that its sonar was pointing directly at the wall which means knowing the orientation of the robot base to the wall? If you have a LIDAR scan you can just plot a path to follow using the LIDAR input.

I have watched a few videos and read a few articles on PID but so far I haven't been able to get an understanding that allows me to code the algorithm into different control systems.

"... ROS may very well be in the future.. but I have to get through the low level goal setting and object avoidance first..."

Personally I find ROS a complicated over kill for a hobby level robot.  Just as the Window's API is overlaid with simple commands useable by a high level computer language (VisualBASIC) so too I would suggest the need for a high level language to program a robot's behaviors and read its sensors without the need to learn ROS.

You say the PID has to be tuned but I think AI would tune itself.

I hope everyone is having a great summer!

Winter here in Australia 🙂

 


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@briang

Tonight I painfully went through your video again. Painful in the sense I have to stop/rewind/write and draw stuff from the video for reviewing. It reminded me of a video on a step by step example of back propagation for an ANN. I had to stop the video, type out the example so far and start it again trying to find a capture without a finger or hand covering parts of it. Eventually I was able to type it up as actual code and run the example to see that it worked giving the outputs it should.

I haven't quite got your example working but I am nearly there I think. When I get it working I will try it out on my robot base with the scanner sonar.

I also noticed your little robot circling the box with a scanner sonar so I guess that is how you determine the distance from the wall from a number of readings.

Also I noticed that there is a PID library which I presume can be used without having a clue how it actually works.

 

 

This post was modified 2 months ago by robotBuilder

ReplyQuote
BrianG
(@briang)
Trusted Member
Joined: 8 months ago
Posts: 70
Topic starter  

@robotbuilder

To you observations / questions around sonar and sensor readings:

Yes, a Lidar 360 degree "map" would be a better input to work off then a few (or even just 1) sonar reading at a particular angle.  It does has the benefit of being easier to learn from though because of the simplicity.  Regardless of the data you are comparing against the set-point however, the algorithm is still the same (the tuning will be different). Most of the sonar based wall following robots I use, take multiple readings at or around 80-90 degrees to track the wall and then also may take readings straight ahead to detect oncoming walls and sometimes another reading at ~55-60 degress which help detect upcoming obstacles or changes in the wall.  These other readings can be summed into the existing PID or have there own PID and then the outputs of all PIDs are summed and go to the wheels.  I tell my students to start with just the 80-90 degree angle and once that is working try to add in other angles as they see fit.

To you ROS point, I am not going to even consider that until I am talking about more high level controllers in a hybrid setup.  I don't see the point of using ROS in single low level controllers, it is just unnecessary overhead, especially when my goal is to teach how to implement the algorithms, not simply just select them from an existing library.

As to the PID in your application, implementing the PID algorithm is just the beginning, tuning it for your physical chassis, motors, controller speed, etc is the most time consuming part usually.  As I mentioned in the video I recommend starting with the P part of the PID.  Since proportional is nice in linear in it's output the easiest way to start is by mapping the input range to the output.  So for example if your sensor input range is 1 to 100 (distance in cm) and your highest motor output is 400 a multiplier of 4x will perfectly map the ranges, so I would start with a Kp of 4 and then observe the result and adjust.

I am not sure which PID library you were referring to at the and I think there is an Arduino one and also a ROS one, but either way, you can use them usually the inputs are the Kp, Ki, Kd and then the ranges to map (sensor input, motor output).  Since you have already translated the mathematics I recommend keeping yours, it will strengthen your understanding which I believe makes the tuning easier.

Hope you are enjoying the winter! 🙂

-Brian

/Brian


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@briang

As to the PID in your application, implementing the PID algorithm is just the beginning, tuning it for your physical chassis, motors, controller speed, etc is the most time consuming part usually. As I mentioned in the video I recommend starting with the P part of the PID. Since proportional is nice in linear in it's output the easiest way to start is by mapping the input range to the output.

I actually experiment on a simple simulated 2D robot base in a world of walkable and unwalkable pixels.

So in the example below the robot is the circle, the green line is the forward looking sonar and the blue line is the side looking sonar. The red line is the path it has taken for a particular algorithm that uses those two inputs. The simulated base also has input for contacting a no go area (black in this case). The sonars are fixed in this case but in other experiments I use a scanner (sonar or lidar) simulator.

wallFollowerTest

And this is the robot base I am using now. I would have to add a sonar scanner to test the PID algorithm.

robotBase1

Since you have already translated the mathematics I recommend keeping yours, it will strengthen your understanding which I believe makes the tuning easier.

Given the goal state (keep a fixed distance from a wall) I suspect you could evolve a wall following controller. Intelligence comes down to achieving some goal. In evolution it is reproductive success at the top and evolved sub goals that enhance the achievement of that goal. A robust machine would be driven by goal states rather than just insect like reflexes. It would adapt its behaviors to environmental changes or physical changes to itself (stuck wheel) that the builder may not have predicted.

Hope you are enjoying the winter! 🙂

It would be nice to have more time to play with the hardware and software but real life intervenes 🙂

 

This post was modified 2 months ago 3 times by robotBuilder

ReplyQuote
BrianG
(@briang)
Trusted Member
Joined: 8 months ago
Posts: 70
Topic starter  

@robotbuilder

If I am following correctly, that simulator (I assume is running your PID?) should allow you to test tuning parameters.  For example if you change 1 of your constants such as Kp constant you should see a different result.  Simulators like that can be a big help!  But how well it translates depends on how well the simulation replicates the actual robot and environment.

And for the second part, PID is intended to be a control algorithm, and act in a very "low level" way.  Methods like this are intended to be much better then say having if - else if - else or case statements trying to account for all possibilities.  PID allows you to react in a natural way.

So far as the high level behaviors go, you can build any you want on top. (Like navigation, object avoidance, mapping, etc).

/Brian


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@briang

If I am following correctly, that simulator (I assume is running your PID?) should allow you to test tuning parameters. For example if you change 1 of your constants such as Kp constant you should see a different result. Simulators like that can be a big help! But how well it translates depends on how well the simulation replicates the actual robot and environment.

With a path like that it isn't using the PID algorithm but I hope to tune and test PID on it once I get the PID working correctly and later do the same on real hardware.  Loading and testing new or modified code on the Arduino controlled robot takes more time. The other project I am working on is having everything including programming done by remote control from a pc (or RPi) and just using the Arduino as a low level controller.

My reason for being here was mainly to learn something from the dronebot robot build or maybe connecting with others who found building and understanding robots at a low level (no libraries) of interest.  However it seems to be all about building a robot by numbers without any low level experimentation on their own software.  I get the impression some see ROS or some library as doing it all for them and it just being a matter of finding someone else's implementation.

So I find following your offerings of interest and will follow the Henry IX build.

 

 

 

This post was modified 2 months ago by robotBuilder

ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@BrianG

Tried to work out the equations to check your manual work through but seem to get the wrong results at T4 where the equations produce a totalError = 21 whereas in the worked out example is a totalError = 16.

Can anyone spot my mistake?

Here is a printout similar to your worked example:

 

T: 1    Error : 20
        prevError: 0
        totalError: 20 = 0 +  20
     Error ->  50   -  30 =  20
     P     ->  4    *  20 =  80
     I     ->  0.5  *  20 =  10
     D     ->  2    * ( 20  -  0) =  40
                           20
     total = 130 =  80 +  10 +  40
--------------------
T: 2    Error : 10
        prevError: 20
        totalError: 30 = 20 +  10
     Error ->  40   -  30 =  10
     P     ->  4    *  10 =  40
     I     ->  0.5  *  30 =  15
     D     ->  2    * ( 10  -  20) = -20
                          -10
     total = 35 =  40 +  15 + -20
--------------------
T: 3    Error : 6
        prevError: 10
        totalError: 36 = 30 +  6
     Error ->  36   -  30 =  6
     P     ->  4    *  6 =  24
     I     ->  0.5  *  36 =  18
     D     ->  2    * ( 6  -  10) = -8
                          -4
     total = 34 =  24 +  18 + -8
--------------------
T: 4    Error :-15
        prevError: 6
        totalError: 21 = 36 + -15
     Error ->  15   -  30 = -15
     P     ->  4    * -15 = -60
     I     ->  0.5  *  21 =  10.5
     D     ->  2    * (-15  -  6) = -42
                          -21
     total =-91.5 = -60 +  10.5 + -42
--------------------
T: 5    Error :-5
        prevError:-15
        totalError: 16 = 21 + -5
     Error ->  25   -  30 = -5
     P     ->  4    * -5 = -20
     I     ->  0.5  *  16 =  8
     D     ->  2    * (-5  - -15) =  20
                           10
     total = 8 = -20 +  8 +  20
--------------------

 Here is the source code written using code::blocks

 

#include <iostream>

using namespace std;

double Kp = 4.0;
double Ki = 0.5;
double Kd = 2.0;

double desired = 30.0;
double actual;

double currentError;
double prevError;
double proportional;
double totalError = 0.0;
double saveErrorSum = 0.0; // save for printout of equation
double integral = 0.0;
double derivative = 0.0;
double pidResult = 0.0;
double av[5] = {50.0, 40.0, 36.0, 15.0, 25.0}; // ;list of actual values

double saveTotalError;

int main( )
{
    for  (int ii;ii<5;ii++){

        actual = av[ii];

        currentError = actual - desired;
        cout << "T:" << ii+1;
        cout << "     Error :" << currentError << endl;
        cout << "        prevError:" << prevError << endl;


        saveTotalError = totalError;
        totalError = totalError + currentError;   // sum of the difference
        cout << "        totalError:" << totalError << " =" << saveTotalError << " + " << currentError << endl;

        cout << "     Error -> " << actual << "   - " << desired << " = " << currentError << endl;

        proportional = Kp * currentError;   // part of the difference values

        //savetotalError = totalError
        cout << "     P     -> " << Kp << "    * " << currentError << " = " << proportional << endl;


        integral = Ki * totalError;           // integral of the difference

        cout << "     I     -> " << Ki << "  * " << totalError << " = " << integral << endl;

        derivative = Kd * ((currentError) - (prevError));  // change in difference of error

        cout << "     D     -> " << Kd << "    * " << "(" << currentError << "  - " << prevError << ") = " << derivative << endl;
        cout << "                         " << (currentError) - (prevError) << endl;

        prevError = currentError;                     //save current error


        pidResult = proportional + integral + derivative;   // add them together

        cout << "     total =" << pidResult << endl;


        cout << "--------------------" << endl;
    }

    cout << "DONE!" << endl;
    return 0;
}

 It can also be run on an Arduino using the Serial Monitor:

 

 

double Kp = 4.0;
double Ki = 0.5;
double Kd = 2.0;

double desired = 30.0;
double actual;

double currentError;
double prevError;
double proportional;
double totalError = 0.0;
double saveErrorSum = 0.0; // save for printout of equation
double integral = 0.0;
double derivative = 0.0;
double pidResult = 0.0;
double av[5] = {50.0, 40.0, 36.0, 15.0, 25.0}; // ;list of actual values

double saveTotalError;

void setup() {

  
  Serial.begin(9600);
  
    for  (int ii=0;ii<5;ii++){

        actual = av[ii];

        currentError = actual - desired;
        Serial.print ("T");
        Serial.print ( ii+1);
        Serial.print (":    Error :");
        Serial.println (currentError);
        Serial.print("        prevError:");
        Serial.println(prevError);


        saveTotalError = totalError;
        totalError = totalError + currentError;   // sum of the difference
        Serial.print("        totalError:");
        Serial.print(totalError);
        Serial.print(" =");
        Serial.print(saveTotalError);
        Serial.print(" + ");
        Serial.println(currentError);

        Serial.print("     Error -> ");
        Serial.print(actual);
        Serial.print("   - ");
        Serial.print(desired);
        Serial.print(" = ");
        Serial.println(currentError);;

        proportional = Kp * currentError;   // part of the difference values

        //savetotalError = totalError
        Serial.print("     P     -> ");
        Serial.print(Kp);
        Serial.print("   * ");
        Serial.print(currentError);
        Serial.print(" = ");
        Serial.println(proportional);


        integral = Ki * totalError;           // integral of the difference

        Serial.print("     I     -> ");
        Serial.print(Ki);
        Serial.print("   * ");
        Serial.print(totalError);
        Serial.print(" = ");
        Serial.println(integral);

        derivative = Kd * ((currentError) - (prevError));  // change in difference of error

        Serial.print("     D     -> ");
        Serial.print(Kd);
        Serial.print("   * ");
        Serial.print("(");
        Serial.print(currentError);
        Serial.print(")  - (");
        Serial.print(prevError);
        Serial.print(") = ");
        Serial.println(derivative);
        Serial.print("                             ");
        Serial.println((currentError) - (prevError));

        prevError = currentError;                     //save current error


        pidResult = proportional + integral + derivative;   // add them together

        Serial.print("     total =");
        Serial.println(pidResult);


        Serial.println("--------------------");
    }

    Serial.println("DONE!");

}

void loop() {
  // put your main code here, to run repeatedly:

}

Here is a version of Brian's example so you don't have to reference the video.

To enlarge image,
Right mouse click image, Open link in new window,

briansPID

 

 

This post was modified 2 months ago 3 times by robotBuilder

ReplyQuote
MadMisha
(@madmisha)
Reputable Member
Joined: 2 years ago
Posts: 319
 

@robotbuilder

Your math checks out. In his video he says "The negative  15 error is added to the positive 36 that we used to have and that leave us with a total error of 16". Bad math, it should be 21.


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@madmisha
@briang

Getting the actual PID equation correct was important and it concerned me I was getting different numbers than the worked example! Math is not my strength 🙁

When teaching myself basic electronics, a long time ago, I found that different books explained the same things better than others. By reading all the books and experimenting with actual circuits I found that I could eventually "get" it.  Same thing with other difficult subjects.

I found this a good starter explanation of the role played by each component in the PID computation to bring about a stable state. Then again maybe it was easy to follow because I had spent time reading and viewing other attempts at explaining PID?

 


MadMisha liked
ReplyQuote
Mark Bolton
(@mark-bolton)
Eminent Member
Joined: 2 months ago
Posts: 48
 

This just looks like empiricism.  When I was in trade school they tried to teach us how to apply Laplace Transforms to these sorts of engineering problems. It went completely over my head. I have attempted to understand it subsequently but without any real success.


ReplyQuote
byron
(@byron)
Honorable Member
Joined: 2 years ago
Posts: 548
 

@robotbuilder

I too thought the video link you posted was a good explanation of PID, I remember viewing it a year or so back.  

I also found the following series on PID to be helpful too.  I though I may as well link the first in the series here to have a bunch of good PID info in one place.

I also liked the PID example @briang covered, and liked the work through of the maths.  This was a great way of presenting it I thought.  (Ok there was a slight error in one of the calculations, and your augmented code going through the maths is a valuable addendum to the video 👍 ) 

 


ReplyQuote
robotBuilder
(@robotbuilder)
Prominent Member
Joined: 2 years ago
Posts: 883
 

@byron

@briang

Personally I find hand written examples tedious and prone to error.  Better to write a program and have it print out the changing values or generate a visual display of what is happening.  There were other issues to the wall following example if you wanted to actually use it on a real robot base which I will not elaborate on as I don't want to hijack the thread. However Brian did want feedback and honestly the example of keeping the ball on the centre of a balance is pure PID where in the video you can see what each component is doing by itself to bring about the desired outcome.

 


ReplyQuote
BrianG
(@briang)
Trusted Member
Joined: 8 months ago
Posts: 70
Topic starter  
Posted by: @robotbuilder

@byron

@briang

Personally I find hand written examples tedious and prone to error.  Better to write a program and have it print out the changing values or generate a visual display of what is happening.  There were other issues to the wall following example if you wanted to actually use it on a real robot base which I will not elaborate on as I don't want to hijack the thread. However Brian did want feedback and honestly the example of keeping the ball on the centre of a balance is pure PID where in the video you can see what each component is doing by itself to bring about the desired outcome.

 

Sorry about the error! Definitely just a misstep on my part.  Thank you for the videos and the feedback!

I have been on vacation this past week with the family and we have one more week ahead, when I come back though I will be putting out the first video on how to localize the robot (and go to goal either in the first video or shortly after) I was able to get the material 90% together before I left but not able to find time to lay down the video and edit. 

I did add another example of potential fields in the git repo, I know a few of you signed up.  It is in the henry ii folder, this one was neat because it took a hybrid approach using the Arduino for low level control (potential fields) and the android app for high level planning (or the start of it).  The android app is outdated (gingerbread as I remember, but could have even been froyo lol..).. But I thought it might be interesting to look through for a second example and also how to setup a connection (this one used serial over standard bluetooth).

@byron Thank you for that video and the feedback as well..

-Brian

 

/Brian


ReplyQuote
Page 8 / 9