package ctbot.utils; import nanovm.ctbot.drivers.Motor; import nanovm.lang.Math; public class Driver { private static float x; private static float y; private static float ori; private static int mode; private static final int DEACTIVATE = 0; private static final int GOTO_XY = 1; private static final int GOTO_ORI = 2; private static final int GOTO_XYORI = 3; private final static float SPEED_FACTOR = 140.0f; private final static float TURN_FACTOR = 10.0f; private final static float TURN_FACTOR_ORI = 10.0f; private final static float M_FINAL_DISTANCE = 0.10f; // 10cm private final static float M_FAR_CIRCLE = 0.20f; // 20 cm private final static float SPEEDUP = 1.00f; // 1.0 (m/s)/m private final static float RAD_FAR_DELTA = 0.01f; // 0.01 rad private final static float M_LANDING_DISTANCE = 0.02f; // 2cm private static float x2; private static float y2; private static float dist; private static float dori; private static float startDist; private static float lastSpeed; private final static float MAX_SPEED = 0.20f; // 20 cm/s private final static float MAX_TURN_SPEED = 0.04f; // 4 cm/s private final static float MAX_SPEED_INC = 0.005f; // 0.5 (cm/s)/tick private final static float MIN_SPEED = 0.01f; // 1 (cm/s) public static void stop(){ Motor.setLeftSpeed(0); Motor.setRightSpeed(0); Motor.setLeft(0); Motor.setRight(0); startDist=Odometry.s; mode=DEACTIVATE; lastSpeed=0.0f; } public static void gotoOri(float targetOri){ x = Odometry.x; y = Odometry.y; x2 = x; y2 = y; ori = Odometry.normalizeOri(targetOri); startDist = Odometry.s; mode = GOTO_ORI; } public static void gotoXY(float targetX, float targetY){ x = targetX; y = targetY; x2 = x; y2 = y; startDist = Odometry.s; mode = GOTO_XY; } public static void gotoXYOri(float targetX, float targetY, float targetOri){ x = targetX; y = targetY; ori = Odometry.normalizeOri(targetOri); x2 = x-M_FINAL_DISTANCE* Math.cos(ori); y2 = y-M_FINAL_DISTANCE*Math.sin(ori); startDist = Odometry.s; mode = GOTO_XYORI; } private static float checkSpeed(float speed, boolean turn){ float distSpeed; if (turn) { distSpeed = Math.max(Math.abs(dori)*0.08f, MIN_SPEED); if (speed>MAX_TURN_SPEED) speed=MAX_TURN_SPEED; if (speed<-MAX_TURN_SPEED) speed=-MAX_TURN_SPEED; } else { distSpeed = Math.max(dist*SPEEDUP, MIN_SPEED); if (speed>MAX_SPEED) speed=MAX_SPEED; if (speed<-MAX_SPEED) speed=-MAX_SPEED; } if (speed>0) speed = Math.min(Math.min(distSpeed, speed), lastSpeed+MAX_SPEED_INC); else speed = Math.max(Math.max(-distSpeed, speed), lastSpeed-MAX_SPEED_INC); lastSpeed=speed; return speed; } private static void goStraight(float speed){ speed=checkSpeed(speed, false); Motor.setLeftSpeed((int)(speed/Odometry.M_PER_TICK)); Motor.setRightSpeed((int)(speed/Odometry.M_PER_TICK)); } private static void goCircle(float radius, float speed){ speed=checkSpeed(speed, false); if (Math.abs(radius)<0.5f*Odometry.M_WHEEL_DISTANCE) { speed /= 0.5f*Odometry.M_WHEEL_DISTANCE; if (radius<0) speed*=-1.0f; } else { speed /= radius; } float speedL = speed * (radius - 0.5f*Odometry.M_WHEEL_DISTANCE); float speedR = speed * (radius + 0.5f*Odometry.M_WHEEL_DISTANCE); Motor.setLeftSpeed((int)(speedL/Odometry.M_PER_TICK)); Motor.setRightSpeed((int)(speedR/Odometry.M_PER_TICK)); } private static void goRotate(float speed){ speed=checkSpeed(speed, true); Motor.setLeftSpeed((int)(speed/Odometry.M_PER_TICK)); Motor.setRightSpeed((int)(-speed/Odometry.M_PER_TICK)); } public static boolean work(){ if (mode==DEACTIVATE) return false; // distance to final target float dx = x-Odometry.x; float dy = y-Odometry.y; dist = Math.sqrt(dx*dx+dy*dy); dori = Odometry.normalizeOri(ori-Odometry.ori); if ((dist<M_LANDING_DISTANCE) | (mode==GOTO_ORI)){ if (mode==GOTO_XYORI) mode=GOTO_ORI; if (mode==GOTO_XY){ stop(); return false; } // landing sequence.... if (dori<0.0f) goRotate(-MAX_SPEED); if (dori>0.0f) goRotate(MAX_SPEED); if (Math.abs(dori)<0.05f){ stop(); return false; } return true; } float gamma = Math.PI-Math.abs(dori); float alpha = nanovm.lang.Math.abs(Odometry.normalizeOri(Odometry.ori - Math.atan2(dx, dy))); float betha = Math.PI-gamma-alpha; // distance to temporary target dx = x2-Odometry.x; dy = y2-Odometry.y; float dist2 = Math.sqrt(dx*dx+dy*dy); if ((dist2>M_FINAL_DISTANCE) || (alpha<betha)){ // we are far away.... float dori2 = Odometry.normalizeOri(Math.atan2(dx, dy)-Odometry.ori); float radius = (0.25f-Math.abs(dori2)/Math.PI)*4.0f; if (Math.abs(dori2)<0.5f*Math.PI) radius=Math.max(radius, 0.10f); else radius = 0.01f; if (dori2>RAD_FAR_DELTA) { goCircle(-radius, MAX_SPEED); } else if (dori2<-RAD_FAR_DELTA) { goCircle(radius, MAX_SPEED); } else { goStraight(MAX_SPEED); } } else { // we are close to the target, final approach.... float radius = dist * Math.sin(betha)/Math.sin(gamma)*Math.tan(0.5f*gamma); if (alpha<0.05f){ goStraight(MAX_SPEED); } else if (dori>0.0f) { goCircle(radius, MAX_SPEED); } else if (dori<0.0f) { goCircle(-radius, MAX_SPEED); } else { goStraight(MAX_SPEED); } } return mode!=DEACTIVATE; } }