All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lejos.robotics.pathfinding.RandomPathFinder Maven / Gradle / Ivy

Go to download

leJOS (pronounced like the Spanish word "lejos" for "far") is a tiny Java Virtual Machine. In 2013 it was ported to the LEGO EV3 brick.

The newest version!
package lejos.robotics.pathfinding;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import lejos.robotics.RangeReading;
import lejos.robotics.RangeReadings;
import lejos.robotics.geometry.Point;
import lejos.robotics.geometry.Rectangle;
import lejos.robotics.mapping.RangeMap;
import lejos.robotics.navigation.DestinationUnreachableException;
import lejos.robotics.navigation.Pose;
import lejos.robotics.navigation.Waypoint;
import lejos.robotics.navigation.WaypointListener;

/**
 * PathFinder that takes a map and a dummy set of range readings.
 * It finds a path that is in short moves, has no obstacles in the
 * way and where valid range readings can be taken from each waypoint.
 * 
 * The algorithm is not deterministic so each time it is called a new route 
 * will be found.
 * 
 * @author Lawrie Griffiths
 *
 */
public class RandomPathFinder implements PathFinder {	
	private static final long serialVersionUID = 1L;
	
	private float minGain = 1;	
	private float clearance = 20;	
	private RangeMap map;
	private RangeReadings readings;
	private float maxRange = 150;
	private float maxDistance = 200;
	private int maxIterations = 1000;
	
	private ArrayList listeners ;
	
	public RandomPathFinder(RangeMap map, RangeReadings readings) {
		this.map = map;
		this.readings = readings;
	}
	
	/**
	 * Set the maximum valid range readings
	 * @param range the maximum range
	 */
	public void setMaxRange(float range) {
		maxRange = range;
	}
	
	/**
	 * Set the maximum distance between waypoints
	 * @param distance the maximum distance
	 */
	public void setMaxDistance(float distance) {
		maxDistance = distance;
	}
	
	/**
	 * Set the maximum number of iterations before giving up when searching for a path
	 * @param iterations the maximum number of iterations
	 */
	public void setMaxIterations(int iterations) {
		maxIterations = iterations;
	}
	
	/**
	 * Set the clearance around the edge of the map.
	 * This does not really work as clearance shiould be around all
	 * walls and obstacles.
	 * 
	 * @param clearance the clearance
	 */
	public void setClearance(float clearance) {
		this.clearance = clearance;
	}
	
	public Path findRoute(Pose start, Waypoint destination)
			throws DestinationUnreachableException {
		Pose pose = start;
		Path route = new Path();
		
		// Continue until we return a route or throw DestinationUnReachableException
		for(;;) {
			// If the current pose if close enough to the destination, 
			// and there are no obstacles in the way, go straight there
			Pose testPose = pose;
			testPose.setHeading(testPose.angleTo(destination));
			if (testPose.distanceTo(destination) < maxDistance &&
					map.range(testPose) >= testPose.distanceTo(destination)) {
				route.add(new Waypoint(destination));
				return route;
			} 
			testPose = null;
			
			// Generate random poses and apply tests to them
			int i;
			for(i=0;i maxDistance) continue;
			    
				// The new pose must be at least MIN_GAIN closer to the destination
				if (pose.distanceTo(destination) - 
						testPose.distanceTo(destination) < minGain)
					continue;
				
				// We must be able to get a valid set of range readings from the new pose
				float heading = testPose.getHeading();
				boolean validReadings = true;
				for(RangeReading r: readings) {
					testPose.setHeading(heading + r.getAngle());
					float range = map.range(testPose);
					if (range > maxRange) {
						validReadings = false;
						break;
					}
				}					
				if (!validReadings) continue;
				
				//Check there are no obstacles in the way 
				testPose.setHeading(testPose.angleTo(pose.getLocation()));
				if (map.range(testPose) < testPose.distanceTo(pose.getLocation()))
					continue;
				//System.out.println("Range = " + map.range(testPose));
				//System.out.println("DistanceTo = " + testPose.distanceTo(pose.getLocation()));
				//System.out.println("From = " + pose);
				//System.out.println("To = " + testPose);
				
				testPose.setHeading(heading); // Restore heading
				break; // We have a new way point
			}
			if (i == maxIterations) throw new  DestinationUnreachableException();
			route.add(new Waypoint(testPose));
			pose = testPose;
		}
	}
	
	/**
	 * Generate a random pose within the mapped area, not too close to the edge
	 */
	private Pose generatePose() {
	    float x, y, heading;
	    Rectangle boundingRect = map.getBoundingRect();
	    Rectangle innerRect = new Rectangle(boundingRect.x + clearance, boundingRect.y + clearance,
	        boundingRect.width - clearance * 2, boundingRect.height - clearance * 2);

	    // Generate x, y values in bounding rectangle
	    for (;;) { // infinite loop that we break out of when we have
	               // generated a particle within the mapped area
	      x = innerRect.x + (((float) Math.random()) * innerRect.width);
	      y = innerRect.y + (((float) Math.random()) * innerRect.height);

	      if (map.inside(new Point(x, y))) break;
	    }

	    // Pick a random angle
	    heading = ((float) Math.random()) * 360;
	    
	    return new Pose(x,y,heading);
	}
	
	public void addListener(WaypointListener wpl) {
	    if(listeners == null )listeners = new ArrayList();
	    listeners.add(wpl);
	  }

	  public void startPathFinding(Pose start, Waypoint end) {
		  Collection solution = null;
		try {
			solution = findRoute(start, end);
		} catch (DestinationUnreachableException e) {
			// TODO Not sure what the proper response is here. All in one.
			return;
		}
		if(listeners != null) { 
			for(WaypointListener l : listeners) {
				Iterator iterator = solution.iterator(); 
				while(iterator.hasNext()) {
					l.addWaypoint(iterator.next());
				}
				l.pathGenerated();
			}
		}
	 }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy