package sim.robot2D;
import sim.physics2D.util.Angle;
//import sim.physics2D.util.Double2D;
import sim.util.matrix.*;
import sim.physics2D.physicalObject.*;
import sim.util.Double2D;
public class Robot extends MobileObject2D
{
private double P_angle;
private double D_angle;
private double P_pos;
private double D_pos;
public Robot()
{
P_angle = 10;
D_angle = 500;
P_pos = .2;
D_pos = 10;
}
protected Double2D localFromGlobal(Double2D globalCoordinate)
{
// x0 = R'x1 - R'T
DenseMatrix global = new sim.util.matrix.DenseMatrix(2, 1);
global.vals[0][0] = globalCoordinate.x;
global.vals[1][0] = globalCoordinate.y;
DenseMatrix T = new sim.util.matrix.DenseMatrix(2, 1);
T.vals[0][0] = this.getPosition().x;
T.vals[1][0] = this.getPosition().y;
double theta = this.getOrientation().radians;
double[][] arR = {{ Math.cos(theta), -Math.sin(theta) },
{ Math.sin(theta), Math.cos(theta) }};
DenseMatrix R = new sim.util.matrix.DenseMatrix(arR);
sim.util.matrix.DenseMatrix local = R.transpose().times(global).minus(R.transpose().times(T));
return new Double2D(local.vals[0][0], local.vals[1][0]);
}
protected Double2D globalFromLocal(Double2D localCoordinate)
{
// x1 = Rx0 + T
Double2D rotated = localCoordinate.rotate(this.getOrientation().radians);
return rotated.add(this.getPosition());
}
/** Gives the angle of the vector (i.e. vector (1, 1) gives PI / 4)
*/
protected Angle getAngle(Double2D vector)
{
// Get the angle
Angle theta;
if (vector.x != 0)
{
theta = new Angle(Math.atan(vector.y / vector.x));
if (vector.x < 0 && vector.y >= 0)
theta = new Angle(Math.PI + theta.radians);
else if (vector.x < 0 && vector.y < 0)
theta = theta.add(Math.PI);
else if (vector.x > 0 && vector.y < 0)
theta = new Angle(Angle.twoPI + theta.radians);
// otherwise (positive x,y quadrant) just theta
}
else
theta = new Angle(vector.y > 0 ? Angle.halfPI : Angle.halfPI * 3);
return theta;
}
protected void faceTowards(Angle globalAngle)
{
double angularVel = this.getAngularVelocity();
double angularError = globalAngle.add(new Angle(-this.getOrientation().radians)).radians;
if (angularError >= Math.PI)
angularError = -(Angle.twoPI - angularError);
double toAdd = P_angle * angularError - D_angle * angularVel;
this.addTorque(toAdd);
}
protected void moveForward(double speed)
{
if (this.getVelocity().length() < speed - .5)
this.addForce((new Double2D(1, 0)).rotate(this.getOrientation().radians));
else if (this.getVelocity().length() > speed + .5)
this.addForce((new Double2D(-1, 0)).rotate(this.getOrientation().radians));
}
protected void goTo(Double2D globalDestination)
{
// First, get the destination in local coordinates
Double2D localDestination = localFromGlobal(globalDestination);
Angle localAngle = getAngle(localDestination);
double angularVel = this.getAngularVelocity();
double angularError;
// Turn towards the target
if (localAngle.radians < Math.PI)
angularError = localAngle.radians;
else
angularError = -(Angle.twoPI - localAngle.radians);
double toAdd = P_angle * angularError - D_angle * angularVel;
this.addTorque(toAdd);
// approach the target
if (Math.abs(angularError) < Math.PI / 15)
{
if (localDestination.length() < 20)
this.addForce((new Double2D(4, 0)).rotate(this.getOrientation().radians));
else
{
double scale = P_pos * localDestination.length() - D_pos * this.getVelocity().length();
Double2D force = (new Double2D(1, 0)).rotate(this.getOrientation().radians).multiply(scale);
this.addForce(force);
}
}
else
{
// otherwise, hit the breaks
this.addForce(this.getVelocity().rotate(Math.PI).multiply(10));
}
}
protected void stop()
{
double angularVel = this.getAngularVelocity();
Double2D vel = this.getVelocity();
this.addForce(vel.rotate(Math.PI).multiply(10));
this.addTorque(-angularVel * 200);
}
protected void backup()
{
Double2D backward = new Double2D(4, 0).rotate(this.getOrientation().add(Math.PI).radians);
this.addForce(backward);
}
}