Plotting the position

Printing out the coordinates is fine for testing, but what we would really like to do is to display the position of the robot on a map of the field displayed on the driver station. For this, we will need a program running on the driver station to handle the plotting of the map. Fortunately, we have one called RobotMapper.  This program connects to the robot, and accepts commands which are used to display the current robot position.  It currently will accept the following two commands (as ascii strings):

c yaw xPos yPos
p yaw xPos yPos

The first character determines the command.  This is followed by the current yaw of the robot (in degrees), and the current X and Y position in inches. the ‘c’ command tells the mapper that the data is coming from the camera, and the ‘p’ command tells the mapper that the data is being computed using the dead reckoning.

The first thing we will need to do is add an instance of our Network class.  We declare it as follows:

	private Network			m_network			= null;

And initialize it in our Init() function:

		m_network	= new Network();
		m_network.Listen(this, k_networkPort);

This creates a new instance of our Network class and then tells it to listen for an incoming network connection on port k_networkPort which is defined as:

	private static final int	k_networkPort	= 5803;

This will be the port to which our RobotMapper program will connect.

After we add this code, we will see that there is an error. This is because we are passing this instance of our Navigator class as the NetworkReceiver parameter of the Listen function.  In order to do this, our Navigator class must implement this interface.  We do this by changing the declaration of our class as follows:

public class Navigator implements NetworkReceiver

When we do this, it then tells us that we need to add the unimplemented methods of the NetworkReceiver interface, which we do as follows:

	@Override
	public void ProcessData(String command) {
		// TODO Auto-generated method stub
		
	}

This function will be called by the Network class whenever it receives messages from the driver station. We will see how we might use this later.

For now, all we need to do is add code to send commands to the RobotMapper program running on the driver station to update the robot’s position and orientation. Change the Update() function to add two SendMessage calls to the Network class as follows:

	private void Update()
	{
		PiCameraData	data 			= Robot.m_piCamera.GetCameraData();
		int				yaw 			= m_gyro.GetYaw();
		int				leftEncoder		= m_leftEncoder.get();
		int 			rightEncoder	= m_rightEncoder.get();
		
		if ((data != null) && IsTargetVisible(data))
		{
			double	top				= (data.m_y1 + data.m_y2) / 2;
			double	center			= (data.m_x + (data.m_width / 2));
			double	angleToCenter	= 0.1014*center - 34.061;
			double	distance 		= (0.000271*top*top + 0.0146*top + 16.64) * (268.46 / (268.46 - 0.0577*angleToCenter*angleToCenter));
			double	angle 			= yaw + angleToCenter;
			double	x 				= -distance * Math.sin(angle * Math.PI/180);
			double	y 				= distance * Math.cos(angle * Math.PI/180);	
		
			synchronized(this)
			{
				m_position	= new RobotPosition(x, y, yaw);
			}

			m_network.SendMessage(String.format("c %.1f %.2f %.2f", m_position.m_yaw, m_position.m_x, m_position.m_y));
		}
		else if (m_position != null)
		{
			double	deltaLeft	= (leftEncoder - m_lastLeftEncoder) / k_ticksPerInch;
			double	deltaRight	= (rightEncoder - m_lastRightEncoder) / k_ticksPerInch;
			double	distance	= (deltaLeft + deltaRight) / 2;
			
			if (distance != 0)
			{
				double	radians	= (m_position.m_yaw * Math.PI) / 180;
				double	deltaX	= distance * Math.sin(radians);
				double	deltaY	= distance * Math.cos(radians);
				
				synchronized(this)
				{
					m_position	= new RobotPosition(m_position.m_x + deltaX, m_position.m_y - deltaY, yaw);
				}
				
				m_network.SendMessage(String.format("p %.1f %.2f %.2f", m_position.m_yaw, m_position.m_x, m_position.m_y));
			}
			
		}
		
		m_lastLeftEncoder	= leftEncoder;
		m_lastRightEncoder	= rightEncoder;
		
		Robot.Sleep(50);
	}

At this point your Navigator.java file should look like:

package robot;

import robot.PiCamera.PiCameraData;
import robotCore.Encoder;
import robotCore.Gyro;
import robotCore.Logger;
import robotCore.Network;
import robotCore.Network.NetworkReceiver;
import robotCore.RobotBase;

public class Navigator implements NetworkReceiver
{
	private static final int	k_networkPort	= 5803;
	private static final double k_ticksPerInch	= 8000.0/38.5;
	
	private Gyro			m_gyro		= new Gyro();
	private RobotPosition	m_position	= null;
	private Encoder			m_leftEncoder		= null;
	private Encoder			m_rightEncoder		= null;
	private int				m_lastLeftEncoder	= 0;
	private	int				m_lastRightEncoder	= 0;
	private Network			m_network			= null;
	
	public class RobotPosition
	{
		public double	m_x;
		public double	m_y;
		public double	m_yaw;
		
		RobotPosition(double x, double y, double yaw)
		{
			m_x		= x;
			m_y		= y;
			m_yaw	= yaw;
		}
	}
	
	public RobotPosition GetPosition()
	{
		synchronized(this)
		{
			return(m_position);
		}
	}
	
	private boolean IsTargetVisible(PiCameraData data)
	{
		return(	(data.m_y1 > 2) &&
				(data.m_y2 > 2) &&
				(data.m_x > 2) &&
				((data.m_x + data.m_width) < 638));
	}
	
	private void Update()
	{
		PiCameraData	data 			= Robot.m_piCamera.GetCameraData();
		int				yaw 			= m_gyro.GetYaw();
		int				leftEncoder		= m_leftEncoder.get();
		int 			rightEncoder	= m_rightEncoder.get();
		
		if ((data != null) && IsTargetVisible(data))
		{
			double	top				= (data.m_y1 + data.m_y2) / 2;
			double	center			= (data.m_x + (data.m_width / 2));
			double	angleToCenter	= 0.1014*center - 34.061;
			double	distance 		= (0.000271*top*top + 0.0146*top + 16.64) * (268.46 / (268.46 - 0.0577*angleToCenter*angleToCenter));
			double	angle 			= yaw + angleToCenter;
			double	x 				= -distance * Math.sin(angle * Math.PI/180);
			double	y 				= distance * Math.cos(angle * Math.PI/180);	
		
			synchronized(this)
			{
				m_position	= new RobotPosition(x, y, yaw);
			}

			m_network.SendMessage(String.format("c %.1f %.2f %.2f", m_position.m_yaw, m_position.m_x, m_position.m_y));
		}
		else if (m_position != null)
		{
			double	deltaLeft	= (leftEncoder - m_lastLeftEncoder) / k_ticksPerInch;
			double	deltaRight	= (rightEncoder - m_lastRightEncoder) / k_ticksPerInch;
			double	distance	= (deltaLeft + deltaRight) / 2;
			
			if (distance != 0)
			{
				double	radians	= (m_position.m_yaw * Math.PI) / 180;
				double	deltaX	= distance * Math.sin(radians);
				double	deltaY	= distance * Math.cos(radians);
				
				synchronized(this)
				{
					m_position	= new RobotPosition(m_position.m_x + deltaX, m_position.m_y - deltaY, yaw);
				}
				
				m_network.SendMessage(String.format("p %.1f %.2f %.2f", m_position.m_yaw, m_position.m_x, m_position.m_y));
			}
			
		}
		
		m_lastLeftEncoder	= leftEncoder;
		m_lastRightEncoder	= rightEncoder;
		
		Robot.Sleep(50);
	}
	
	public void Init()
	{
		m_gyro.Reset();
		
		m_leftEncoder	= Robot.m_driveSubsystem.GetLeftEncoder().Clone();
		m_rightEncoder	= Robot.m_driveSubsystem.GetRightEncoder().Clone();
		
		RobotBase.Schedule(new Runnable() 
			{
				@Override
				public void run() 
				{
					Update();
				}
			
			}, 50);
		
		m_network	= new Network();
		m_network.Listen(this, k_networkPort);
	}

	@Override
	public void ProcessData(String command) {
		// TODO Auto-generated method stub
		
	}
}

Before you run your program, launch the RobotMapper program by double clicking on the RobotMapper.cmd file in the PiUtil folder.  Then launch your program and drive the robot around.  Remember that you need to align the robot so that it pointing directly at the tower to get the zero point of the gyro set correctly.

You should see it’s position tracked on the map.  You will notice that when the robot can see the tower you see only one green marker.  When the robot cannot see the tower, you see both a red and green marker.  The green marker shows the robot’s position using the dead reckoning, and the red marker shows the last position where the robot could see the tower.

Next: Drive to position