space.craft.ed
space.craft.ed space for everyone

space for everyone

mission

Our objective is to inspire high school students to explore space with depth and sustainability — to be useful, challenging, empowering, and self-supporting.

Clubs form their own space service, dividing into specialist teams — command & control, launch, mission, satellite, and datacoms — collaborating like a real agency.

Command & Control

Coordinates all teams to build capabilities and maintain safety.

Launch Services

Create launchers to reach different altitudes and lift payloads safely.

Mission Services

Develop sensors and platforms for data collection using micro:bit or Raspberry Pi.

Satellite Services

Design payload carriers that separate and descend safely.

Datacoms

Handle telemetry, radio links, and data visualisation.

Communications

Promote achievements, document missions, and connect with the public.

micro:bit – Sputnik (Beacon)

Goal: simulate a satellite beacon transmitting an identifier and simple telemetry.

// Beacon sound-only
let id = 42
basic.forever(function() {
  music.playTone(880, music.beat(BeatFraction.Eighth))
  basic.showNumber(id)
  basic.pause(400)
})
// Radio beacon (sender)
radio.setGroup(7)
let id2 = 42
basic.forever(function(){
  radio.sendValue("id", id2)
  radio.sendNumber(input.acceleration(Dimension.Z))
  basic.pause(200)
})

micro:bit – Acceleration

Capture Z-axis acceleration during launch and descent; view graphs and export CSV.

// Serial logger
let logging = true
serial.writeLine("time,z")
basic.forever(function(){
  if(logging){
    serial.writeValue("z", input.acceleration(Dimension.Z))
    basic.pause(50)
  }
})
// Radio link sender
radio.setGroup(10)
basic.showString("Z TX")
basic.forever(function(){
  radio.sendNumber(input.acceleration(Dimension.Z))
  basic.pause(50)
})
// Radio receiver
radio.setGroup(10)
serial.writeLine("time,z")
radio.onReceivedNumber(function(v){
  serial.writeValue("z", v)
})

micro:bit – Temperature

Log the board temperature (or ambient if isolated from heat).

// Temperature logger
serial.writeLine("time,tempC")
basic.forever(function(){
  serial.writeValue("tempC", input.temperature())
  basic.pause(500)
})

micro:bit – Stability

Display tilt arrows and log pitch/roll for attitude analysis.

serial.writeLine("time,pitch,roll")
basic.forever(function(){
  let pitch = input.rotation(Rotation.Pitch)
  let roll = input.rotation(Rotation.Roll)
  serial.writeValue("pitch", pitch)
  serial.writeValue("roll", roll)
  if(Math.abs(pitch)<10 && Math.abs(roll)<10){
    basic.showIcon(IconNames.SmallDiamond)
  } else if(Math.abs(pitch)>Math.abs(roll)){
    basic.showArrow(pitch>0?ArrowNames.South:ArrowNames.North)
  } else {
    basic.showArrow(roll>0?ArrowNames.East:ArrowNames.West)
  }
  basic.pause(100)
})

micro:bit – Test Pilot

Show a face that reflects flight smoothness using accelerometer variance.

// Smoothness face
let buf:number[]=[]
const N=15
basic.forever(function(){
  let ax=input.acceleration(Dimension.X)
  let ay=input.acceleration(Dimension.Y)
  let az=input.acceleration(Dimension.Z)
  let mag=Math.sqrt(ax*ax+ay*ay+az*az)
  buf.push(mag); if(buf.length>N)buf.shift()
  let avg=buf.reduce((a,b)=>a+b,0)/buf.length
  let varr=buf.reduce((a,b)=>a+(b-avg)*(b-avg),0)/buf.length
  if(varr<5000){basic.showIcon(IconNames.Happy)}
  else if(varr<20000){basic.showIcon(IconNames.Asleep)}
  else{basic.showIcon(IconNames.Sad)}
  basic.pause(50)
})

Raspberry Pi – Weather

Log temperature, humidity, and pressure as a weather payload.

# weather_sensehat.py
from sense_hat import SenseHat
from time import time,sleep
import csv
sense=SenseHat(); FN='weather.csv'
with open(FN,'w',newline='') as f:
  w=csv.writer(f); w.writerow(['t_s','temp_c','humidity','pressure_hpa'])
  t0=time()
  try:
    while True:
      row=[round(time()-t0,2),
           round(sense.get_temperature(),2),
           round(sense.get_humidity(),2),
           round(sense.get_pressure(),2)]
      w.writerow(row); f.flush(); sleep(0.5)
  except KeyboardInterrupt: print('Saved',FN)

Raspberry Pi – Camera

Capture still images during flight; optionally trigger on liftoff detection.

# cam_interval.py — capture 1 photo/sec
from picamera2 import Picamera2
from time import time,sleep
from pathlib import Path
picam=Picamera2(); picam.configure(picam.create_still_configuration()); picam.start()
out=Path('photos'); out.mkdir(exist_ok=True)
i=0
try:
  while True:
    fn=out/f\"img_{i:04d}.jpg\"; picam.capture_file(str(fn))
    print('saved',fn); i+=1; sleep(1.0)
except KeyboardInterrupt: pass
finally: picam.stop()
# cam_triggered.py — burst when acceleration rises
from picamera2 import Picamera2
from sense_hat import SenseHat
from math import sqrt
from time import sleep
from pathlib import Path
sense=SenseHat(); picam=Picamera2()
picam.configure(picam.create_still_configuration()); picam.start()
out=Path('photos'); out.mkdir(exist_ok=True)
THRESH=2000; buf=[]
def amag():
  ax,ay,az=sense.get_accelerometer_raw().values()
  return int(1000*sqrt(ax*ax+ay*ay+az*az))
n=0
try:
  while True:
    a=amag(); buf.append(a); buf=buf[-10:]; avg=sum(buf)/len(buf)
    if avg>THRESH:
      for k in range(5):
        fn=out/f\"burst_{n:04d}_{k}.jpg\"; picam.capture_file(str(fn))
        print('burst',fn); sleep(0.2)
      n+=1
    sleep(0.05)
except KeyboardInterrupt: pass
finally: picam.stop()

Sponsors

Partner with us to inspire the next generation of space engineers. Contact METAMORPHORCES for collaboration opportunities.

Log In

Member login coming soon — future integration will include secure SSO and team dashboards.