Presenting NXTLineLeader with leJOS 0.9

This is where you talk about the NXJ hardware related topics such as the brick, sensors, LEGO pieces, etc

Moderators: roger, 99jonathan, imaqine

Presenting NXTLineLeader with leJOS 0.9

Postby MattG » Sun Jul 17, 2011 12:19 pm

Hi guys,
I’m very excited to present you my work with the NXTLineLeader-Sensor from Mindsensors.

I’m using the current Version of LeJOS(0.9) and also the new included NXTLineLeader class.
Unfortunately I wrote my own NXTLineLeader class some month ago and I thought I got something new ;-). But my class and the class of LeJOS 0.9 are almost the same. Anyway… the class of LeJOS 0.9 works fine and the assumed mistakes in this Thread are wrong.
I got some trouble at the beginning with the new leJOS update because they changed the motor class. There is no setPower()-method anymore… and the NXTLineLeaders Firmware is calculating a value you should add or subtract from the power (i.e. to subtract the value from left wheel and add it to right wheel or vice versa) and not from the speed. Therefore you need to use an unregulated motor. Otherwise the NXTLineLeader doesn’t work fine. Andy explained something about the new motor class here, which is every time regulated (you can’t turn this off anymore).
Fortunately I found the NXTMotor class in LeJOS which is still supporting the setPower()-Method and which supports an unregulated Motor. Of course you have to disclaim some motor methods… but for my work the NXTMotor Class implements all functions I needed.
Otherwise you gotta use an older LeJOS version and use your own (or my) NXTLineLeader class like I did it before the new update 0.9 came out.


I did some tests with the class and the NXTLineLeader sensor and I’m absolutely surprised what u can do with it… it’s a revolution in line-following and it works great…
I implemented my own PID-Algorithm to test if the sensor works fine… and yes, it does ;-).

At my university we always had some trouble to follow lines and also to print the lines on huge papers… but this sensor is so sophisticated that u can just use a black marker. We could just follow lines in low power but now a power of 100 is no problem.

I built my car with an OmniWheel because it’s easier and better to follow the line. You have no unnecessary attrition with this wheel which could infect a good linefollowing.

Look at my videos:
Here I’m just drawing a line (not just straight, rather twisted) (9mm) and it’s no problem for my LineLeader. I tested also different width for the line: 5mm is possible, but 8-10mm is good. Perfect is 12mm.
http://www.youtube.com/watch?v=e-OfVm_eRp4


It is also possible to follow acute angles. Here I’m using insulating tape (12mm)
http://www.youtube.com/watch?v=NA5P1qFyMjY


At least I did some tests to show u the PID-Algorithm working. I can change the PID values and the SetPoint (this says the sensor under which area he attempts to follow the line (default is the center of the sensor) of the NXTLineLeader
http://www.youtube.com/watch?v=mcwERdaZJeU


I can’t post the source of my class at this moment, because it is part of my academic work. But when it’s graded, I will post it here ;-).
At the moment I’m writing a program for navigation with the LineLeader on a grid with the help of the A*Algorithm. I’m almost done. I will post it here in a few days…


Im looking forward to get some feedback… :-)

Cheers
Matt
MattG
New User
 
Posts: 4
Joined: Sun Jul 17, 2011 12:06 pm

Re: Presenting NXTLineLeader with leJOS 0.9

Postby Walt White » Thu Jul 21, 2011 6:40 pm

Matt,

I checked the YouTube videos: Great work! Very impressive with the acute angles!

I'm still hoping to get time this weekend to try my project again. And I will be greatly interested in seeing your PID program when it's available for public use.

Walt
Walt White
Novice
 
Posts: 43
Joined: Sun Aug 06, 2006 11:57 pm
Location: California Central Valley

Re: Presenting NXTLineLeader with leJOS 0.9

Postby kirkpthompson » Thu Jul 21, 2011 10:53 pm

Walt, there is a generic PID Controler class in LeJOS you may want to examine: lejos.util.PIDController:
http://lejos.svn.sourceforge.net/viewvc/lejos/trunk/classes/lejos/util/PIDController.java?sortby=file&view=log

Best,
-K
Leg Godt!
User avatar
kirkpthompson
leJOS Team Member
 
Posts: 282
Joined: Wed Dec 05, 2007 1:27 am
Location: New Mexico, USA

Re: Presenting NXTLineLeader with leJOS 0.9

Postby MattG » Tue May 01, 2012 12:48 pm

Hi guys,

Many months later Ive posted my videos Im allowed now to publish my code for my NXTLineLeader... its just the code to make the lineleader following a line.... like you can see in the youtube-videos. maybe somebody is looking for something like this ;-)
There is a small program included for the NXT-Display where you can change some settings.... like speed and so on....

CU

Code: Select all


import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.MotorPort;
import lejos.nxt.NXTMotor;
import lejos.nxt.SensorPort;
import lejos.nxt.addon.NXTLineLeader;


/**
 * This class directs the LineLeader with the help of the NXTLineLeader-Sensor by mindsensors.com
 * over a black line.
 * It is possible to change PID-Values, SetPoint, Power and OverLineMode through NXT-Screen
 * while running the programm
 *
 * @author MattG
 */
public class LineLeader {
   
   
    //Include the own NXTLineLeader-Class
    //static MSLineLeader liner = new MSLineLeader(SensorPort.S2);
    static NXTLineLeader liner = new NXTLineLeader(SensorPort.S2);
    static NXTMotor MotorA = new NXTMotor(MotorPort.A);
    static NXTMotor MotorC = new NXTMotor(MotorPort.C);
   
   
    public static void main(String[] args) throws InterruptedException {
              LineLeader ll = new LineLeader();
             ll.Calibration();
             ll.followLine();
     }
 
    /**
    * This method calibrates the Sensor. Follow the instructions on the NXT-Screen
    *
    * @throws InterruptedException
    */
   public void Calibration() throws InterruptedException {
         
          liner.wakeUp();
          //liner.setStatus('P'); // own NXTLineLeader Class
         LCD.drawString("Calibration: ", 0, 0);
           LCD.drawString("Place LineLeader", 0, 1);
           LCD.drawString("over bright area ", 0, 2);
           LCD.drawString("Press Enter", 0, 3);
           Button.ENTER.waitForPressAndRelease();
           LCD.drawString("**** wait ******", 0, 3);
           liner.calibrate(NXTLineLeader.LineColor.WHITE); //calibrate white color
           //liner.calibrateSensor('W'); // own NXTLineLEader Class
           LCD.clear();
              
           LCD.drawString("Calibration: ", 0, 0);
           LCD.drawString("Place LineLeader", 0, 4);
           LCD.drawString("over black area ", 0, 5);
           LCD.drawString("Press Enter", 0, 6);
           Button.ENTER.waitForPressAndRelease();
           LCD.drawString("**** wait ******", 0, 7);
           liner.calibrate(NXTLineLeader.LineColor.BLACK); //calibrate black color
           //liner.calibrateSensor('B'); // own NXTLineLEader Class
           LCD.clear();
           LCD.drawString("Calibration done", 0, 4);
           LCD.clear();

       }
   
      
    /**
     * Try to maintain the line according to the settings
     *
    * @throws InterruptedException
    */
   public void followLine() throws InterruptedException {
         
           // Set OverLineMode at the beginning
           int overLineModus=change_overLineMode(0);
         
         // Some inits for the LineLeader
         liner.setSetPoint(45);
         liner.setKP(44); liner.setKI(0); liner.setKD(3);
           int lastResult = -1; int lastSteering = 0;
           MotorA.forward(); MotorC.forward(); int power = 100;
           //int lastError=0; //if u use ur own PID u nedd this

           
           while (!Button.ESCAPE.isPressed())
           {   
              // to change the PID during driving
              if(Button.ENTER.isPressed()){ LCD.clear(); Thread.sleep(1000); change_PID();}
                // to change the speed during driving
              if(Button.LEFT.isPressed()){ LCD.clear(); Thread.sleep(1000); power=change_speed(power);}
              // to change the setPoint during driving
              if(Button.RIGHT.isPressed()){LCD.clear(); Thread.sleep(1000); overLineModus=change_overLineMode(overLineModus);}       
 
              
              int llResult = liner.getResult();
            
              //Print information and some interesting values on Screen
                LCD.clear();
             LCD.drawString("ENTER: PID", 0, 0);
             LCD.drawString("LEFT: Power", 0, 1);
             LCD.drawString("RIGHT: Mode", 0, 2);
              LCD.drawString("Result:", 0, 4);
              LCD.drawString("               ",0,5);
              LCD.drawString(Integer.toBinaryString(llResult), 0, 5);
              LCD.drawInt(llResult, 11, 5);
              LCD.drawString("Steering:", 0, 6);   
               LCD.drawString("Average:", 0, 7);
               LCD.drawString("    ",11,6);
              LCD.drawInt(liner.getSteering(), 11, 6); 
              LCD.drawString("    ",11,7);
               LCD.drawInt(liner.getAverage(), 11, 7);
               
              
                if (lastResult != llResult) {
                
                   
                   if(llResult==255){ // All sensors read black
                      MotorA.stop();
                      MotorC.stop();
                 }
                   
                   else if(llResult==0){ // All sensor read white
                      // Correct the course like the last steering
                      if(lastSteering>0){if(overLineModus==0)MotorA.stop();else MotorA.setPower(-power);}
                      else {if(overLineModus==0)MotorC.stop(); else MotorC.setPower(-power);}

                    }
                   
                   else {
                
                        //My Own Steering
                        /*
                      int error = liner.getAverage()-liner.getSetPoint();
                        int integral = integral + error;
                        int derivative = error - lastError;
                        double kp = liner.getKP();
                        double kpd = liner.getKPDivisor();
                        double ki = liner.getKI();
                        double kid = liner.getKIDivisor();
                        double kd = liner.getKD();
                        double kdd = liner.getKDDivisor();
                        int steering2 = (int)(((kp/kpd)* error) +((ki/kid)*integral)+((kd/kdd)*derivative));
                        lastError = error;
                        LCD.drawString("    ",11,6);
                        LCD.drawInt(steering2, 11, 6);
                        */
                       
                      
                   int steering = liner.getSteering();
                   MotorA.setPower(power - Math.abs(steering) - steering);
                   MotorC.setPower(power - Math.abs(steering) + steering);
                   MotorA.forward(); MotorC.forward();
                   lastSteering = steering;
                }
                lastResult = llResult;
             }
               
     
             
         
          } //End while
       }
   
      
      /**
       * This method can change KP, KI, KD, SetPoint
       *
       * @throws InterruptedException
       */
      public void change_PID() throws InterruptedException {   
         
         // KP
         int value = liner.getKP();
         LCD.drawString("SET KP", 0, 0);
         LCD.drawString("0 to 255", 0, 1);
         LCD.drawString("VALUE:", 0, 2);
         
         while(!Button.ENTER.isPressed()){         
            if(Button.LEFT.isPressed() && value>0)value -= 1;
            if(Button.RIGHT.isPressed() && value<255)value += 1;
            LCD.drawString("    ", 7, 2);
            LCD.drawInt(value, 7, 2);
            Thread.sleep(200);
            }
         Thread.sleep(1000);
           LCD.clear();
         liner.setKP(value);

         // KI
         value = liner.getKI();
         LCD.drawString("SET KI", 0, 2);
         LCD.drawString("0 to 255", 0, 3);
         LCD.drawString("VALUE:", 0, 4);
         
         while(!Button.ENTER.isPressed()){         
            if(Button.LEFT.isPressed() && value > 0)value -= 1;
            if(Button.RIGHT.isPressed() && value < 255)value += 1;
            LCD.drawString("    ", 7, 4);
            LCD.drawInt(value, 7, 4);
              Thread.sleep(200);
         }
         Thread.sleep(1000);
           LCD.clear();
         liner.setKI(value);
         
         // KD
         value = liner.getKD();
         LCD.drawString("SET KD", 0, 4);
         LCD.drawString("0 to 255", 0, 5);
         LCD.drawString("VALUE:", 0, 6);
         
         while(!Button.ENTER.isPressed()){         
            if(Button.LEFT.isPressed() && value > 0)value -= 1;
            if(Button.RIGHT.isPressed() && value < 255)value += 1;
            LCD.drawString("    ", 7, 6);
            LCD.drawInt(value, 7, 6);
            Thread.sleep(200);
         }
         Thread.sleep(1000);
          LCD.clear();
         liner.setKD(value);
         
         //SetPoint
         value = liner.getSetPoint();
         LCD.drawString("SetPoint", 0, 0);
         LCD.drawString("10 to 80", 0, 1);
         LCD.drawString("VALUE:", 0, 2);
         
         while(!Button.ENTER.isPressed()){         
            if(Button.LEFT.isPressed() && value > 10)value -= 5;
            if(Button.RIGHT.isPressed() && value < 80)value += 5;
            LCD.drawString("    ", 7, 2);
            LCD.drawInt(value, 7, 2);
            Thread.sleep(200);
         }
         liner.setSetPoint(value);
         Thread.sleep(1000);
         LCD.clear();
         LCD.drawString("Press Enter", 0, 5);
         LCD.drawString("to follow", 0, 6);
         LCD.drawString("the line", 0, 7);
         Button.ENTER.waitForPressAndRelease();
      }
      
      
      /**
       * If the LineLeader lost the line, he needs to correct his position
        *
       *
       * @param overLineMode
       *                      0: Turn back to line in a circle
       *                      1: Turn back to line on place
       * @return the new OverLineMode
       * @throws InterruptedException
       */
      public int change_overLineMode(int overLineMode) throws InterruptedException {   
         LCD.clear();
         int value = overLineMode;
         LCD.drawString("SET OverLineMode", 0, 0);
         LCD.drawString("0:Turn in circle ", 0, 2);
         LCD.drawString("1:Turn on point", 0, 3);
         LCD.drawString("Current VALUE:", 0, 6);
         
         while(!Button.ENTER.isPressed()){            
            if(Button.LEFT.isPressed() && value > 0)value -= 1;
            if(Button.RIGHT.isPressed() && value < 1)value += 1;
            LCD.drawString(" ", 15, 6);
            LCD.drawInt(value, 15, 6);
            Thread.sleep(200);
         }
         Thread.sleep(1000);
         LCD.clear();
         LCD.drawString("Press Enter", 0, 5);
         LCD.drawString("to follow", 0, 6);
         LCD.drawString("the line", 0, 7);
         Button.ENTER.waitForPressAndRelease();
         return value;
      }
      
   
      /**
       * @param power current power
       * @return the new power value
       * @throws InterruptedException
       */
      public int change_speed(int power) throws InterruptedException {   
         
         int value = power;
         LCD.drawString("SET Power ", 0, 0);
         LCD.drawString("0 to 100", 0, 1);
         LCD.drawString("VALUE:", 0, 2);
         
         while(!Button.ENTER.isPressed()){         
            if(Button.LEFT.isPressed() && value > 5)value -= 5;
            if(Button.RIGHT.isPressed() && value < 100)value += 5;
            LCD.drawString("    ", 7, 2);
            LCD.drawInt(value, 7, 2);
            Thread.sleep(200);
         }
         Thread.sleep(1000);
         LCD.drawString("Press Enter", 0, 5);
         LCD.drawString("to follow", 0, 6);
         LCD.drawString("the line", 0, 7);
           Button.ENTER.waitForPressAndRelease();
         return value;
      }
}


SET KI
MattG
New User
 
Posts: 4
Joined: Sun Jul 17, 2011 12:06 pm


Return to NXJ Hardware

Who is online

Users browsing this forum: No registered users and 0 guests

more stuff