Project Suncatcher: A Prototype Satellite Is Now in Orbit
Our Project Suncatcher prototype satellite is in orbit, according to the project's primary source. This article separates what that source verifies from what remains open, and outlines practical questions AI teams should ask before planning around orbital infrastructure for research and model deployment.
Tags
Quick summary
Our Project Suncatcher prototype satellite is in orbit, according to the project's primary source. This article separates what that source verifies from what remains open, and outlines practical questions AI teams should ask before planning around orbital infrastructure for research and model deployment.
Project Suncatcher: A Prototype Satellite Is Now in Orbit
A prototype satellite for Project Suncatcher is now in orbit. That is the headline, and it comes from a single primary source: Google's AI blog post at https://blog.google/innovation-and-ai/models-and-research/google-research/project-suncatcher-prototype, with an associated timestamp of 2026-10-01T23:30:00.000Z.
That is a short sentence. It is also, for anyone running AI and data infrastructure, the kind of sentence that starts a long chain of engineering work. Once hardware is on orbit, the interesting problems migrate from design documents to ground systems: knowing where the object is, when you can talk to it, how you ingest what it sends, and how you tell the difference between "nothing arrived" and "something arrived but was wrong."
This article stays inside what the source actually supports. It does not speculate about the payload, the orbit, the launch vehicle, or the downlink plan, because the announcement does not establish those. What it does instead is lay out the ground-segment work that any "prototype is in orbit" milestone implies, with concrete, runnable tooling you can adapt.
What the Source Establishes — and What It Does Not
The verified claim is narrow and worth restating precisely: a Project Suncatcher prototype satellite is in orbit. The claim is backed by an accessible primary source, which puts it at a strong evidence level for a single fact.
Everything below that line is inference. The source does not, on its face, give us:
- an object identifier or catalog number,
- orbital elements, altitude, inclination, or expected lifetime,
- a frequency plan or modulation scheme,
- any statement about payload capability, compute, power, or data volume,
- any performance claim or benchmark,
- a statement about whether the spacecraft is merely in orbit or fully commissioned and healthy.
This matters because the name "Suncatcher" invites a specific story — solar collection, energy beaming, orbital compute — and none of that is established by a headline that says a prototype is in orbit. The honest reading is: a milestone was reached, and the engineering consequences begin now.
Why "In Orbit" Is a Ground-Software Milestone
For a research team, getting a prototype into orbit is usually a hardware and launch milestone. For the surrounding software organization, it is the moment a set of previously theoretical interfaces become live contracts.
Three things change at once:
The telemetry source becomes physical. Until launch, telemetry can be simulated with a fixture. After launch, the fixture is a radio, and the failure modes are physical: a pass that never rises above the elevation mask, a capture that starts late, a noisy frame that passes a length check and fails a checksum.
Time becomes a hard dependency. Pass prediction is a time-domain computation. If a ground station's clock drifts by a second, tracking degrades; if it drifts by a minute, you miss the window and there is no retry until the next orbit.
Idempotency stops being optional. A frame may arrive twice, arrive partially, or fail decoding and need reingestion from a raw capture. Systems that treat ingestion as append-only tend to accumulate silent duplicate records.
None of these are exotic. They are the ordinary discipline of any pipeline whose upstream is unreliable. The useful move is to build that discipline before the first pass, not after the first data gap.
A Ground-Segment Pattern You Can Reuse
The pattern below is deliberately generic. It is not official Project Suncatcher tooling, and it does not assume anything the announcement does not state. It is a reference implementation for a small ground segment: TLE-based pass prediction, a capture step, and a structured telemetry ingestion path.
Think of it as scaffolding you replace piece by piece as real interface documentation arrives.
Requirements
Before installing anything, confirm the following:
- Operating system: a Linux distribution with a current package manager. Commands below assume a Debian- or Ubuntu-derived system.
- Python: 3.11 or newer. The
skyfieldlibrary depends on modern packaging and numerical libraries. - Clock discipline: an NTP client such as
chrony. Pass prediction on a drifting clock is a self-inflicted wound. - Network access: outbound HTTPS to a public satellite catalog so you can pull current element sets.
- Optional SDR hardware: an RTL-SDR-class receiver is sufficient to prove the capture path end to end before investing in a higher-grade radio.
- Disk: enough space for raw IQ captures. These grow quickly, so plan retention before your first long capture.
- A satellite identity: an object name or catalog number from your operator or your own catalog entry. The announcement does not publish one, so this must come from elsewhere.
Step-by-step installation
Start by installing the system packages. This brings in Python, a clock daemon, the SDR user-space tools, and a graphical pass-prediction client for manual verification.
sudo apt update && sudo apt install -y python3 python3-venv python3-pip chrony rtl-sdr gpredictConfirm the clock is being disciplined before you trust any timing output.
chronyc trackingCreate an isolated Python environment so the pipeline's dependencies do not collide with system packages.
python3 -m venv .venv && source .venv/bin/activateUpgrade the packaging tools inside the environment, then install the three libraries the reference scripts use: skyfield for orbital propagation, requests for catalog and webhook calls, and pyyaml for configuration.
pip install --upgrade pip && pip install skyfield requests pyyamlVerify the environment resolves correctly. If the import prints a version, you have a working propagation stack.
python -c "import skyfield, requests, yaml; print(skyfield.__version__)"Create the directory layout the rest of this article assumes. Separating config, data, and logs keeps raw captures out of your code tree and makes retention policies straightforward.
mkdir -p suncatcher-ground/{config,data,logs}Configuration
Create a single configuration file. Every value that the source does not establish is left as an explicit placeholder rather than a plausible-looking default, so nobody mistakes an assumption for a fact.
cat > suncatcher-ground/config/ground.yaml <<'YAML'
station:
name: "station-01"
latitude_deg: 0.0 # set to your ground station
longitude_deg: 0.0 # set to your ground station
elevation_m: 0
catalog:
tle_url: "https://celestrak.org/NORAD/elements/gp.php?GROUP=active&FORMAT=tle"
object_name: "REPLACE-WITH-OPERATOR-SUPPLIED-NAME"
passes:
elevation_mask_deg: 10.0
horizon_hours: 24
capture:
downlink_mhz: null # NOT published; take from the operator's ICD
sample_rate_hz: 2400000
output_dir: "data/raw"
telemetry:
schema_version: 1
max_frame_bytes: 512
alert_webhook: "https://example.invalid/hooks/ground" # replace or set null
YAMLNow write the pass-prediction script. It loads the catalog once, builds a topocentric view from your station, and samples the next window at a fixed cadence to find when the object clears the elevation mask. Replace the object name with the identifier you obtained from your operator.
# suncatcher-ground/passes.py
import yaml
from skyfield.api import load, wgs84
with open("config/ground.yaml") as fh:
cfg = yaml.safe_load(fh)
ts = load.timescale()
url = cfg["catalog"]["tle_url"]
sats = {s.name: s for s in load.tle_file(url)}
sat = sats[cfg["catalog"]["object_name"]]
station = cfg["station"]
topos = wgs84.latlon(
station["latitude_deg"], station["longitude_deg"], station["elevation_m"]
)
difference = sat - topos
mask = cfg["passes"]["elevation_mask_deg"]
horizon = cfg["passes"]["horizon_hours"]
for minute in range(0, horizon * 60, 1):
t = ts.utc(ts.now().utc_datetime().replace(second=0, microsecond=0))
t = ts.tt_jd(t.tt + minute / 1440.0)
alt, az, _ = difference.at(t).altaz()
if alt.degrees >= mask:
print(f"{t.utc_iso()} alt={alt.degrees:6.1f} az={az.degrees:6.1f}")Write the ingestion script next. The frame parser below is intentionally a stub: it enforces a maximum length and a checksum slot, but you must replace verify_checksum with the real scheme from the interface documentation. Keeping that function isolated means the day the ICD arrives, you change one function instead of the pipeline.
# suncatcher-ground/ingest.py
import hashlib
import json
import yaml
with open("config/ground.yaml") as fh:
cfg = yaml.safe_load(fh)
MAX = cfg["telemetry"]["max_frame_bytes"]
def verify_checksum(frame: bytes) -> bool:
"""PLACEHOLDER: replace with the checksum defined in the interface document."""
if len(frame) < 5:
return False
body, declared = frame[:-4], frame[-4:]
computed = hashlib.sha256(body).digest()[:4]
return computed == declared
def parse_frame(frame: bytes) -> dict:
if len(frame) > MAX:
raise ValueError("frame exceeds configured maximum length")
if not verify_checksum(frame):
raise ValueError("checksum mismatch")
return {
"schema_version": cfg["telemetry"]["schema_version"],
"length_bytes": len(frame),
"payload_hex": frame[:-4].hex(),
"digest": hashlib.sha256(frame).hexdigest(),
}
if __name__ == "__main__":
import sys
raw = open(sys.argv[1], "rb").read()
print(json.dumps(parse_frame(raw), indent=2))Usage examples
Predict the next day of usable passes. This is the command you run before scheduling anything else, and it is also the fastest way to confirm your station coordinates are correct.
cd suncatcher-ground && python passes.py | head -n 20Capture raw IQ during a pass. The frequency is read from an environment variable because it is not published in the announcement; set it from the operator's documentation. Always confirm the dongle is visible before a time-critical window.
rtl_test -tThen capture, writing to a timestamped file so repeat passes never overwrite each other.
export DOWNLINK_MHZ=000.000 # set from operator documentation
rtl_sdr -f ${DOWNLINK_MHZ}M -s 2400000 data/raw/pass_$(date -u +%Y%m%dT%H%M%SZ).iqRun a frame through the parser to confirm your checksum logic behaves as expected against real bytes.
python ingest.py data/raw/frame_0001.binFinally, if you configured a webhook, send a heartbeat after each pass so a missing alert is itself an alert. Silent pipelines are the ones that fail for weeks unnoticed.
# suncatcher-ground/heartbeat.py
import requests, yaml
cfg = yaml.safe_load(open("config/ground.yaml"))
url = cfg["telemetry"].get("alert_webhook")
if url:
requests.post(url, json={"station": cfg["station"]["name"], "status": "pass_complete"}, timeout=5)What Remains Open
The most useful thing a technical reader can take from this milestone is a clear map of the unknowns. The source confirms a prototype is in orbit. It does not confirm operational status, data return, or any capability claim. Until an object identifier and interface documentation exist, every number in your configuration — frequency, modulation, frame format, pass cadence — is a placeholder waiting to be replaced by something authoritative.
That is not a weakness in the announcement. It is simply where the boundary of public evidence sits, and treating it as such is what keeps a ground segment honest.
Conclusion
A prototype satellite in orbit is one line of text and a large amount of downstream engineering. The work that follows is unglamorous but tractable: disciplined clocks, reproducible pass prediction, captures that never overwrite each other, and an ingestion path whose unknown parts are explicitly labeled as unknown.
The reference pipeline above installs in minutes and does not pretend to know more than the source does. Use it to prove your ground segment end to end now, keep every unpublished value as a named placeholder, and swap in the real interface specification the moment it exists.



