Goals and Objectives

We have specified the hardware and software requirements for the Base-station in Section Components of Project 4. Please, recall that the base-station is comprised of the following:
  1. a Kinect camera,
  2. a workstation to process depth data from the Kinect sensor,
  3. a micro-controller based wireless transmitter to transmit required speeds and radii to the satellite station.


Figure 1: Workstation of the base-station showing the three tracked Roomba robots. It also shows the transmitter module.



Figure 2: The tracker camera with the workstation. The image was taken before plugging in the the trajectory transmitter. Recall that the base-station is comprised of a workstation, a Kinect sensor, and a micro-controller based transmitter.

All these modules are physically connected together and communicate over USB cables.

Note that the workstation is mainly responsible for computing the locations of the tracked Roomba robots. In Section Kinect Tracker we will describe that in detail.

These three modules communicate in a very specific manner -- in a sequential one direction manner only. The sequence is ordered as follows:
  1. The workstation first reads the depth values from the Kinect sensor. It then computes the current position and then if necessary computes any adjustment in speeds and radii for the satellite stations.
  2. The workstation then transmits these values to the transmitter by a serial port.
  3. The transmitter then transmits these values to the satellite stations by radio.
We will maintain this order when we describe the implementation in this section.

Reading depth values

Reading the depth values from the Kinect camera is very easy. As mentioned in Project 4, we use the Processing programming language and its IDE to read the depth data. In the following listing we give a complete example that collects depth and RGB values from the camera and plots the 3D point cloud with the actual colour of the points.

import SimpleOpenNI.*;
import processing.opengl.*;
import peasy.*;

SimpleOpenNI kinect;
PeasyCam camera;

void setup()
{
  kinect = new SimpleOpenNI(this);
  kinect.enableDepth();
  kinect.enableRGB();
  size(kinect.depthWidth(), kinect.depthHeight(), OPENGL);
}


void draw()
{
  kinect.update();
  background(0);
  drawPointCloud();
  translate(width/2, height/2);
  kinect.drawCamFrustum();
}

void drawPointCloud()
{
  int[] depthMap = kinect.depthMap();
  int steps = 3;
  int index;
  
  PVector realWorldPoint;
  stroke(255);
  for (int y = 0; y < kinect.depthHeight(); y += steps){
    for (int x = 0; x < kinect.depthWidth(); x += steps){
      index = x + y * kinect.depthWidth();
	  stroke(kinect.rgbImage().pixels[index]);
      if (depthMap[index] > 0){
        realWorldPoint = kinect.depthMapRealWorld()[index];
        point(realWorldPoint.x, realWorldPoint.y, realWorldPoint.z);
      }
    }
  }
}

Listing 1: A complete example in Processing language to get started with the Kinect depth data.

The only requirement for this to run is a workstation that has a graphics card that can support at least Open GL version 2.1. The PeasyCam is also a Processing library. We use it to rotate the 3D camera for different views of the point cloud.

Tracker sending values to the transmitter

The workstation, having computed the current 3D positions of the satellite stations and necessary adjustments in speeds and radii needed for each of the tracked stations, transmits data to the transmitter serially connected to the workstation. This communication is also implemented in the Processing language. In particular, the workstation writes 12 bytes to a COM port.
port.write( char (a_speed/256) );
port.write( a_speed & 0xFF );
port.write( char (a_radius/256) );
port.write( a_radius & 0xFF );

port.write( char (b_speed/256) );
port.write( b_speed & 0xFF );
port.write( char (b_radius/256) );
port.write( b_radius & 0xFF );

port.write( char (c_speed/256) );
port.write( c_speed & 0xFF );
port.write( char (c_radius/256) );
port.write( c_radius & 0xFF );
Listing 2: Processing source code that writes to the COM port for the transmitter to pick up this data.

An RTOS based Transmitter

The transmitter is implemented using an RTOS we developed in Project 3. The transmitter is comprised of four periodic tasks. Each of these tasks has a period of 20 RTOS ticks, that is, 100 ms. The periodic tasks perform the following roles.
  1. Read values from the tracker.
  2. Transmit the required speed and radius to a satellite station. Each such periodic task transmits data to a pre-determined satellite stations only. As we have three such stations, we therefore have three such periodic task.
Listing 3 shows part of AVR code of r_main of the RTOS.

Task_Create_Period(read_desired_speeds_and_radii, A, 20, 5, 20);
Task_Create_Period(send_to_station_a, B, 20, 2, 28);
Task_Create_Period(send_to_station_b, C, 20, 2, 1004);
Task_Create_Period(send_to_station_c, D, 20, 2, 1008);
Listing 3:AVR code showing the periodic tasks creation. The first periodic task reads speed and radius values for each of the three satellite stations. It reads twelve bytes of data ten times a second.

received_bytes = bytes_received();
if (received_bytes == 12){ 
/*Note: Hard coded number, Potential source of error */

	a_speed = read_byte(0) * 256 + read_byte(1);
	a_radius = read_byte(2) * 256 + read_byte(3);
	
	b_speed = read_byte(4) * 256 + read_byte(5);
	b_radius = read_byte(6) * 256 + read_byte(7);
	
	c_speed = read_byte(8) * 256 + read_byte(9);
	c_radius = read_byte(10) * 256 + read_byte(11);

	reset_receive();	
}
Listing 4: AVR code that reads data from the workstation.

The other three periodic tasks transmits speed and radius data to the respective satellite stations they are assigned to.

packet_a.payload.message.messagecontent[0] = (a_speed >> 8);
packet_a.payload.message.messagecontent[1] = (a_speed & 0xFF);
packet_a.payload.message.messagecontent[2] = (a_radius >> 8);
packet_a.payload.message.messagecontent[3] = (a_radius & 0xFF);
Radio_Set_Tx_Addr(station_a_addr);
Radio_Transmit(&packet_a, RADIO_RETURN_ON_TX);

Listing 5:AVR code that transmits speed and radius data to a satellite station.