September 8, 2016

The Circle Tutorial

Hug Me

There are two kinds of objects in the SPHERES universe, those that have a fixed position and those that don’t. In some games an object only appears at a fixed position so we always know where it is. Other objects can have a variable position so we must ask the API for their positions. In some cases we might also be able to ask for an object’s orientation. This varies from competition to competition. In the case of the satellites, we can get much more information. There are two sets of API function calls that get satellite “state” information. For the purposes of this tutorial, we will only deal with one set, getMyZRState and getOtherZRState. Each of these functions return an array of 12 floats that describe a satellite’s position, velocity, orientation and rate of rotation. You can think of this 12 element float array as a collection of four 3-dimensional vectors. (The other state functions return orientations in the form of quaternions which are represented as a 4-dimensional vector.)

Let’s try a simple example by flying over to the other satellite. The approach is simple, ask the API where the other satellite is with getOtherZRState() and then go there with setPositionTarget().

Re-write the loop() function like this.

void loop(){
    DEBUG(("\nHello Space! Time: %d",time));
 
    float OtherState[12];
    api.getOtherZRState(OtherState);
    api.setPositionTarget(OtherState);
     
    time++;
}

When you run this simulation, you will see the blue satellite fly over to the red satellite and end up occupying the same space. This code works by defining an array of 12 floats (OtherState) to hold the state information for the other satellite. The API call to getOtherZRState then fills this array with the state information for the other satellite. Finally, we use setPositionTarget to move us to that position. Notice that we didn’t explicitly tell our satellite where to go, we simply “followed” a stationary opponent. This same code will follow a moving opponent as well, which is something you should try along the way. Also notice that there is no reference to red or blue. We simply get the “other” satellite’s state, so this program will work running as the red satellite by chasing the blue one. Always remember that in competition sometimes you’ll be blue and sometimes you’ll be red, and you should always test your programs both ways. 

You can determine your own state by creating an array of 12 floats and calling api.getMyZRState() to fill it. Knowing your own state is vital because noise and variability in the system make dead reckoning an unreasonable approach to navigation. Another classic ZR challenge is determining if you are the red or blue satellite.

Can you think of a way to tell?

During the first call to loop() check your position. In any given game the red and blue satellites will start in specific places. 

int sphere = myState[1]>0?1:-1;

which to us humans means that if the y component of myState is greater than 0 then set the variable “sphere” to be 1 otherwise set it to -1. (Of course this assumes that you’ve loaded myState with getMyZRState().)The use of 1 and -1 for sphere numbers can be helpful because often targets in the ZR game are on one side of the field for red and the other for blue. For example an item might be at position <0,.5,0> for the blue satellite and <0,-.5,0> for the red satellite. If you fly to the position defined by <0,sphere*.5,0> you will go to the correct position regardless of which satellite you are. If you don’t see this now, don’t panic, simply let this sit in the back of your brain and sit until you get into competition and one day out of the blue (or red) it’ll hit you.

It may look funny that we are passing an array of 12 floats into setPositionTarget when it only needs an array of 3 floats, but in reality we are passing a pointer to memory and the function simply reads the next three values. This works because the first 3 floats of myState represent the position of the satellite. Following that are the velocity (3 floats), the orientation (3 floats) and the rotation rates (3 floats.) If you name your array myState you can reference the values using the following syntax:

  • &myState[0] – Position 
  • &myState[3] – Velocity
  • &myState[6] – Orientation
  • &myState[9] – Rotation Rate

(&myState[0] is the same as myState as they both point to the first position of the array.)

In real matches two satellites can’t occupy the same space so to protect them, a collision avoidance system (a.k.a. CA) kicks in and overrides the satellite’s control system to keep the two apart. CA also tries to prevent the satellites from hitting the walls. (Although I did see a satellite on the ISS do that once – no worries, they bounce.) In FreeMode CA is turned off.

You may want to copy this program to a new name (i.e. HugMe) to play with later when you have more interesting satellites to chase. You can do this by clicking File and then Save As from the IDE menu. When the Save As dialog box comes up, enter the new program name and click Submit. You should notice that you are now in the new program. Regardless of whether you made the copy or not, return to the My Projects screen by clicking File and Save & Return to Projects.