Skip to content

3. Competitor Python API

AlexSein98 edited this page Oct 19, 2026 · 6 revisions
Back to Wiki Home

How to run the sim

  1. Open Space Teams PRO through SpaceCRAFT.exe, and log in.
  2. Open Sim from the main menu and select the User made sim checkbox on the left.
  3. Select Repos/STU4-Sim/Sims/COMPETITION_SIM.simconf, then select Confirm.

Where To Add Your Code

Start with:

  • Controller.py - the Python file that will be run from the sim config in STU4-Sim.
  • BasicController.py - example of main autonomous-controller template.
  • UserAPI.py - example of a smaller API-oriented example for reading state and sending commands.

The recommended workflow is to edit the user-code section of Controller.py, below the two large boilerplate markers. Keep the simulator connection boilerplate and all helper functions unchanged!

Reading Shuttle State

The common objects are initialized in each controller (e.g., in BasicController.py):

this = st.GetThisSystem()
shuttle = this.GetParam(st.VarType.entityRef, "Shuttle")
phobos = this.GetParam(st.VarType.entityRef, "Phobos")
target = this.GetParam(st.VarType.entityRef, "Target")

Useful state queries include:

state = shuttle.getLocVelAcc()
location = state.loc_WRT_ExprIn(phobos.GetBodyFixedFrame())
velocity = state.vel_WRT_ExprIn(phobos.GetBodyFixedFrame())
rotation = shuttle.getRotation()
angular_velocity = shuttle.getAngVelocity()
mass = shuttle.getMass()
inertia = shuttle.getInertiaTensor(shuttle.GetBodyFixedFrame())
damage = shuttle.GetParam(st.VarType.double, ["Stats", "Damage"])

The target's position can be read in the same frame:

target_state = target.getLocVelAcc()
target_location = target_state.loc_WRT_ExprIn(phobos.GetBodyFixedFrame())

Always make frame conversions explicit. The simulation uses the Phobos-centered reference frame for mission geometry and the shuttle's body-fixed frame for actuator commands.

Time

The initial simulation time can be obtained as follows:

t0_sim: st.timestamp = st.SimGlobals.GetSimEntity().GetParam(st.VarType.timestamp, ["Time", "StartDateTAI"])
t0: datetime.datetime = t0_sim.as_datetime()

It is recommended that you set this up at the beginning of your script. At any subsequent point, you can then obtain the time (in seconds) from the simulation start as follows:

t_now: datetime.datetime = st.SimGlobals.SimClock.GetTimeNow().as_datetime()
t_from_start: float = (t_now - t0).total_seconds()

Sending Commands

Use the helper already provided by BasicController.py:

SetCommand(linear_acceleration, angular_acceleration)

Both arguments are NumPy 3-vectors:

  • linear_acceleration: $\text{m/s}^2$, expressed in the shuttle's body frame.
  • angular_acceleration: $\text{rad/s}^2$, expressed in the shuttle's body frame.

Example:

linear_acceleration = np.array([0.0, 0.0, 1.0])
angular_acceleration = np.zeros(3)
SetCommand(linear_acceleration, angular_acceleration)

Thruster acceleration is limited by each thruster's maximum thrust force. Excessive acceleration commands are capped to within the vehicle's available acceleration.

Radar And Debris Data

The radar system publishes noisy debris observations to the shuttle. The nearest observations are available through the helper:

debris = GetNearestDebrisLocations(N)

where $N$ is the number of observed debris to get. Set this number to whatever your controller needs to process, up to a maximum of 500. Each returned item is a doubleM3x3 array:

debris_center = item[0, :]          # m, Phobos-fixed-frame coordinates
closest_range = item[1, 0]          # m, range to closest part of debris, with sphere shape assumption
range_rate = item[1, 1]             # m/s, positive is increasing range
radar_diameter = item[1, 2]         # m
t_since_start = item[2, 0]          # seconds

The array is sorted nearest to furthest distance from vehicle to debris center.

Controlling the Cameras

BasicController.py exposes TopCamera and BottomCamera. To point a camera, use:

PanTiltCamera(topCamera, yaw_degrees, pitch_degrees)

The helper clamps the angles to the camera's supported range. Camera image capture is available through the Space Teams camera API and is useful for debugging what the shuttle can currently see or for building a simple vision-based target detector.

A typical capture flow looks like this:

cameraParams = st.CaptureImageProperties()
cameraParams.nonphys_EV = 12.0
cameraParams.FOV = 60.0
cameraParams.ResolutionX = 512
cameraParams.ResolutionY = 512
image = st.camera.CaptureImageBlocking(topCamera, cameraParams)

st.camera.CaptureImageBlocking will wait until the image has captured and has been returned from the simulation. This may take hundreds of milliseconds during each call.

Solution Validity

It is intended for competitors to only change python code in Controller.py, and add additional scripts if necessary. Using any library, framework, dataset, or other tool is allowed, as long as you are legally allowed to submit the full source code (or, for example, pip package names) to us as part of your submission. We must be able to run your solution code on our own computers to validate your solution. Additionally, keep the following in mind:

  • Retrieving debris information through the sim (i.e., via debris.getLocation() and similar functions), instead of through the limitations of the radar and the camera, is not allowed.
  • Directly affecting entity motion through functions other than the thruster commands is not allowed.
  • Changing entity physics, scoring, System activation, thruster data, or other sim config/entity config data is not allowed.

If you have questions about this, please ask on the Forum.

Minimal Beeline Example

This example points acceleration toward the target without using radar or obstacle detection:

shuttleFrame = shuttle.GetBodyFixedFrame()

shuttle_state = shuttle.getLocVelAcc()
shuttle_location = shuttle_state.loc_WRT_ExprIn(phobosFrame)
shuttle_velocity = shuttle_state.vel_WRT_ExprIn(phobosFrame)

target_state = target.getLocVelAcc()
target_location = target_state.loc_WRT_ExprIn(phobosFrame)

to_target = target_location - shuttle_location
distance = np.linalg.norm(to_target)
if distance > 1.0:
    direction = to_target / distance
    desired_velocity = 10.0 * direction
    acceleration = desired_velocity - shuttle_velocity
    acceleration = st.frames.FramedVector(acceleration, phobosFrame).ExprIn(shuttleFrame)
    SetCommand(acceleration, np.zeros(3))
else:
    SetCommand(np.zeros(3), np.zeros(3))

This is only a starting point. A competitive controller should account for noisy radar observations, relative velocity, acceleration limits, attitude, debris geometry, fuel usage, and the scoring tradeoff between speed and damage.