September 8, 2016

The Circle Tutorial

Run Away

It’s about time we get our satellite moving, so let’s drive! As a rule we use the code in loop() to decide how we want to control our satellite, and then use the API functions to instruct the hardware (or simulator) on what to do.

There are several sets of API functions that are generally used to control the motion of the satellite. API functions are called using “api.” followed by the function name (i.e. api.setPositionTarget.)

The following API functions control the position of the satellite:

api.setPositionTarget() takes a location vector as a parameter and is the ZR equivalent of jumping into a taxi and saying “Take me to this place,” and handing the driver an address. There is one a little catch. You need to remind the driver where you want to go every second until you get there. This function is easy to use, but you leave all the decisions up to the “driver” and that may not always be the best choice.
api.setVelocityTarget() takes a velocity vector as a parameter and accelerates the satellite in an attempt to match the desired velocity.
api.setForces() takes a force vector as a parameter and fires the jets to apply the requested force to the satellite.
The following API functions control the orientation of the satellite:

api.setAttitudeTarget() takes an orientation vector as a parameter and turns the satellite to point to that orientation.
api.setAttRateTarget() takes a rotation rate vector as a parameter and attempts to set all of the rotation rates to match the requested rates.
api.setTorques() takes a torque vector as a parameter and fires the jets to apply the requested torques to the satellite.
These functions need to be called every second. The satellite’s momentum carries it along, but the control routines won’t run or fire the jets if they are not called in a given second. So if you want to use api.setPositionTarget to get to a specific location, you must call the function every time loop() is called until you arrive at that location — more on that later. There are many other API control commands as well, but this is already more than we need right now.

We will be introducing vectors in more detail, but for the moment, just trust me and create a new variable “vec.” This time we are going to create it as part of the loop() function itself. This is because we only need to use it within this function and its value doesn’t need to be remembered between successive calls to loop(). Add the following two lines directly after the DEBUG statement.

float vec[3]={0.0f,0.0f,0.13f};

Now run the program and view the simulation. You should see the blue satellite travel down and left and then stop. Look at the simulation screen and note the position displayed for the blue satellite. This is in the upper left of the screen labelled X:, Y: and Z:. If you watch these numbers for a while you’ll notice that they stop somewhere around X:0.0 Y:0.0 Z:0.13, but the numbers will vary some due to noise in the system. Hopefully your satellite has traveled roughly to the position <0,0,0.13>.

The other values in the satellite’s status box are velocity (Vx,Vy,Vz), orientation (Nx,Ny,Nz) and rate of rotation (Wx,Wy,Wz). You should also see the name of your program at the top of this box.

Return to the program and replace setPositionTarget with setVelocityTarget, re-run it and view the simulation. This will smoothly accelerate the satellite to a velocity of <0,0,0.13> and then hold that velocity. You will see the satellite fly off the bottom edge of the “universe” and loop around to the top and fly back down the screen. In competition the “universe” is bounded and this will not happen.

Now return to the program and replace setVelocityTarget with setForces, re-run and view the simulation. This will accelerate the satellite full tilt in the +z direction (yup, down) with no velocity limit.

Now try the program three more times using setAttitudeTarget, setAttRateTarget and setTorques. You should get similar results except that instead of the satellite moving, it will be rotating. setAttitudeTarget should rotate the satellite to a specific orientation and stop. setAttRateTarget will attempt to rotate at a specific rate and hold that rate. And setTorques will apply a rotational force without limit. So now you know how to move and rotate, but knowing how to how to do it is of little help if you don’t know where you are and where you want to go. In the next section we’ll work on this. For now simply commit your program using the Commit option on the IDE menu.


For those of you doing the f=ma calculations, you should know that the mass of the satellite is ~4.45kg. Unfortunately, this makes it look like f doesn’t equal ma. There are a few very important facts that you need to understand about the satellite system to reconcile this.

The jets on the satellite only fire a maximum of 20% of each second.
They generally fire in pairs.
The max. thrust from each of those jets is .098N.
Given the above information can you calculate the maximum acceleration?
accMax = 2 thrusters * 0.098N * 0.2 s / 4.45kg = 0.0088m/s^2
There is a ZR FAQ article about this here.