Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SkyHook

Non-sidereal tracking and continuous autofocus for equatorial mounts.

赤道仪天生只会做一件事:以恒星速率(15.041"/s)绕极轴转动,好让星星钉在视场里。 SkyHook 让它学会做另一件事——追上会动的东西:从头顶掠过的飞机、LEO 卫星、气球、无人机, 并且在目标距离不断变化的同时,把焦点一直咬住。

核心是标准库实现(零第三方依赖),天文算法与硬件协议全部可选可插拔。

skyhook sim --scenario satellite --duration 120
SkyHook 0.2.0 -- simulating 'satellite' for 120 s of target time
site: site (39.90420, 116.40740, 50 m)
start: RA 272.9886  Dec +30.2797  el 21.5  range 1245205 m
predictor: model + bias

results
  cycles          600
  tracked samples 582
  error mean      5.7"        <- 而仿真器自身注入了 14" 周期误差 + 22" 齿隙
  error rms       9.1"
  error p95       18.9"
  max RA rate     2999"/s
  range           991414 .. 1230331 m
  focuser         20003 .. 20004

Important

先读 docs/HARDWARE.md 里的速率上限一节。 这不是软件能绕过去的限制:一架 10 km 外的客机需要约 0.5°/s 的轴速度, 过天顶的 LEO 卫星需要 1°/s 以上,而很多消费级赤道仪的自定义跟踪速率上限远低于此。 追不上不是 bug,是机械现实。


目录


它到底解决了什么

追一个移动目标,困难不在"知道它在哪",而在知道命令抵达时它会在哪

三份延迟会叠加:

延迟来源 典型值 后果
数据源陈旧 ADS-B 位置约 1 s 更新一次,读到时已过期 900 km/h 的飞机偏出 ~250 m
指令传输 10–150 ms(串口最慢) 按当前位置发命令,永远慢半拍
机械响应 轴速率一阶收敛,0.1–0.3 s 新速率要过一会儿才建立

SkyHook 的处理方式:

  1. 按数据源给出的时间戳与速度做前向外推(ADS-B 的 seen_pos 直接用上);
  2. 卡尔曼滤波估计位置/速度/加速度,并带野值剔除——一次错误报文不该把望远镜甩飞;
  3. 提前量(lead):速率指令按 t + lead 时刻的目标状态计算,命令生效时正好合上;
  4. 读数外推:望远镜回传的位置本身也是旧的,用它自己的速率推回"现在"再比误差;
  5. 输出的是速率而非"转到某点"——每 200 ms 发一次 GoTo 会让赤道仪一直在启停,图像抖动、机械磨损。

30 秒上手

不需要任何硬件,不需要装任何包。

git clone https://github.com/aronsirius/skyhook
cd skyhook

# 纯标准库,连 pip install 都不需要
python -m skyhook sim --scenario aircraft --duration 120
python -m skyhook sim --scenario satellite --duration 120

# 加上真实感的噪声:25 m 位置误差、0.35 s 时间抖动、5% 丢包
python -m skyhook sim --scenario aircraft --duration 120 --noise

# 对焦表:不同距离该把调焦座拧到哪
python -m skyhook focus --distances 500 3000 30000 1e9

# 自检
python -m skyhook selftest
python -m skyhook info

仿真用的是虚拟时钟:120 秒的目标时间通常 1 秒内跑完,因此 CI 里也能跑回归测试。

想看实时曲线:

python -m skyhook track --config config/skyhook.toml --dashboard
# 打开 http://127.0.0.1:8765/

工作原理

      ADS-B / TLE / synthetic           相机(可选)
              |                              |
              v                              v
      +----------------+             +----------------+
      |  TargetSource  |             |  sharpness /   |
      |  统一输出视位置 |             |  centroid      |
      +----------------+             +----------------+
              |                              |
              |  ra, dec, rate, range        | 清晰度 / 像面偏移
              v                              |
      +-------------------------------------------+
      |            TargetPredictor                |
      |  物理模型(可选) + 卡尔曼残差  ->  t+lead   |
      +-------------------------------------------+
                          |
                          v  ra, dec, dRA/dt, dDec/dt
      +-------------------------------------------+
      |              TrackingLoop                 |
      |  误差 = 目标(现在) - 望远镜(外推到现在)     |
      |  指令 = 前馈速率 + Kp*误差 + Ki*∫误差      |
      +-------------------------------------------+
                 |                        |
                 v                        v
        +----------------+      +--------------------+
        |     Mount      |      |  FocusController   |
        | 绝对速率 arcsec/s|     | 距离前馈 + 温度    |
        +----------------+      | + 清晰度爬山        |
                                +--------------------+

为什么输出"绝对速率"

硬件接口大多要的是相对恒星速的偏移,而控制律天然产生绝对速率。 这个转换统一放在驱动边界(mount/base.py):

offset_ra  = absolute_ra - 15.0410686   # ASCOM Alpaca / INDI 都是这个语义
offset_dec = absolute_dec               # 赤纬轴没有恒星分量

另外:RA 轴速率是沿赤经轴的速率,不是天空角速度,所以全项目不乘 cos(dec)

model + bias:为什么要它

对卫星,TLE 传播器能给出长期正确的轨迹,但绝对精度只有公里级; 让多项式去外推整段过境会发散。所以:

  • 模型负责长期行为(propagate/kepler.py 或 skyfield/SGP4)
  • 滤波器只估计残差(TLE 误差、折射残差、时间偏差),残差变化缓慢,CV 模型足够

飞机没有可信的长期模型,就退回滤波器独立外推(含加速度项)。

支持矩阵

赤道仪 驱动 非恒星速率 备注
ASCOM Alpaca alpaca ✅ 原生 推荐。跨平台、无 COM、无 32/64 位坑
INDI indi ✅ 原生 Raspberry Pi + Ekos 的默认选择
LX200 串口 lx200 ⚠️ 脉冲近似 协议本身没有连续速率命令,见下
任何 GoTo(应急) lx200 ⚠️ 脉冲 用导星脉冲补差,会有几角秒锯齿
仿真 sim 延迟、齿隙、周期误差、限幅全都有

LX200 的现实:标准命令集没有"设置连续跟踪速率"这一条。驱动提供两种模式—— pulse(用方向键脉冲补差,通用但有几角秒锯齿)和 custom (填你固件的私有命令模板,例如 rate_command_ra = ":RA{rate:+.5f}#")。 真要做高精度非恒星跟踪,请走 Alpaca 或 INDI。

目标源

说明
adsb dump1090 / readsb / tar1090 的 aircraft.json;本地文件或 URL 都行
satellite TLE 文件;装了 skyfield 自动升级为完整 SGP4
synthetic 合成轨迹,用于仿真、演示、回归测试

相机(对焦反馈用)

说明 依赖
sim 内置光学模型,随调焦座位置改变模糊
alpaca ASCOM Alpaca 相机
opencv USB / 网络摄像头 opencv-python
directory 回放 PGM/PPM 序列,适合离线调参 无(其他格式需 Pillow)

实测精度

skyhook sim 的数字,仿真器注入了 14" 周期误差 + 22" 齿隙 + 1.1" 抖动 + 0.08 s 指令延迟

场景 误差均值 RMS P95 峰值轴速率
客机(无噪声) 3.1" 6.0" 5.7" ~1600"/s
客机(25 m 噪声 + 0.35 s 抖动 + 5% 丢包) 114" 144" 287" ~4800"/s
LEO 卫星(model + bias) 5.7" 9.1" 18.9" ~3000"/s
LEO 卫星(仅滤波器) < 60" ~3000"/s

噪声场景的 114" 值得解释:ADS-B 在 30 km 外 25 m 的位置误差本身就是 ~170", 加上 0.35 s 抖动 × 240 m/s ≈ 84 m ≈ 580"。滤波器把它们压到 114"(约 16 m), 但压不到零——这是数据源的物理极限,不是算法问题。 想再进一步只能靠图像闭环测目标质心(见路线图)。

自动对焦

薄透镜关系决定了全部设计:

1/f = 1/u + 1/v      =>      Δv = v - f = f²/(u - f)
  • 1000 mm 望远镜拍 3 km 外的飞机:调焦座要外移 0.33 mm。按 2.5 µm/步算是 130 步—— 数值不大,但远大于景深,不能不管。
  • 500 km 外的卫星:0.000002 mm。等价于无穷远,所以卫星只需要温度补偿。

控制器按可信度排序使用三种输入:

  1. 距离前馈(主力)——斜距已知时直接算位置;飞机 20 秒内距离能减半,必须跟上。
  2. 温度补偿——碳纤/铝管的每度漂移,不补的话前两项白做。
  3. 清晰度爬山(兜底)——对目标周围 ROI 的拉普拉斯方差做爬山, 只在一个有界偏移量内微调,吸收模型不知道的东西(滤镜轮后截距变化、镜筒形变、steps_at_infinity 标定误差)。
$ python -m skyhook focus --distances 500 3000 30000 1e9

optics: 1000 mm f/5, 4000 steps/mm (0.25 um/step)
hyperfocal distance: 10,001 m (beyond this, infinity focus is fine)

    distance   offset mm     steps    delta          depth of field
         500      2.0040     28016    +8016         476 ..        526
       3,000      0.3334     21334    +1334       2,308 ..      4,285
      30,000      0.0333     20133     +133       7,501 ..        inf
1,000,000,000      0.0000     20000       +0      10,001 ..        inf

注意 30 km 那一行:远近界变成了 7501 .. inf——超过了超焦距, 远处全部清晰,于是再远的目标都共用无穷远对焦。这就是为什么卫星不用调焦。

相机:把对焦闭环接上

上面三项里,前两项(距离、温度)不需要图像就能算;第三项要。没有相机时 sharpness_fn 是空的,爬山不启动——对焦仍然工作,但只靠模型,对后截距变化、 镜筒形变这类"模型不知道的事"无能为力。

# 先看一眼相机和指标是否正常:扫描应当是一条干净的单峰
python -m skyhook cam --kind sim --sweep --sweep-from 19800 --sweep-to 20200 --sweep-step 50

# 全程跟踪 + 真实像素驱动对焦
python -m skyhook sim --camera sim --duration 60

支持四种源:sim(内置光学模型)、alpaca(ASCOM 相机)、opencv(USB/网络摄像头)、 directory(回放 PGM/PPM 序列,适合离线调参)。

ROI 是这里唯一容易设错的东西。 清晰度指标是在裁剪窗口上取的平均值, 噪声的贡献是每像素固定的、不随窗口缩小而减少,而目标的信号集中在十几个像素里。 窗口开得越大,信号被摊薄、噪声不减:实测 90×90 时峰底比只有 1.1(等于没有信号), 16×16 时是 23.5。所以窗口要紧紧框住目标,而不是"大一点保险"。

配置

TOML(Python 3.11+ 自带 tomllib,所以依然零依赖)。从 config/skyhook.toml 抄一份改。

最小可用配置:

[site]
lat_deg = 39.9042
lon_deg = 116.4074
height_m = 50.0

[mount]
kind = "sim"

[source]
kind = "synthetic"

[loop]
cycle_s = 0.2
lead_s = 0.45

lead_s 是最值得调的一个数:它应该等于指令延迟 + 机械响应时间常数。 Alpaca 一般 0.3–0.5 s;串口 LX200 可以到 0.6 s。调小了会滞后,调大了会超前震荡。

接真机

  1. kind = "sim" 先跑通,确认站址、时间、目标源都对。
  2. alpaca(或 indi),先不接相机,只看 error_total_as 能不能稳定。
  3. 标定对焦:对准一颗亮星,手动调到最锐,把步数填进 steps_at_infinity; 再用两个已知距离的目标(或一次 --direction 试错)确定 directionsteps_per_mm
  4. 第一次实战挑目标:远处高空客机(角速度 100–300"/s)比头顶飞过的近距飞机容易得多。

细节见 docs/HARDWARE.md,公式见 docs/MATH.md

测试与开发

python -m unittest discover -s tests      # 81 项,约 2 秒,不需要硬件
python -m skyhook selftest

测试里最有价值的是 tests/test_control.py:它把整条闭环跑起来, 断言误差量级。如果有人改坏了提前量补偿或速率单位换算,这些数字会涨一个数量级—— 比断言某个内部变量有意义得多。

python -m pip install -e ".[dev]"          # 开发
python -m pip install -e ".[sat]"          # 完整 SGP4
python -m pip install -e ".[serial]"       # LX200 串口
python -m pip install -e ".[all]"

已知限制

诚实清单:

  • 轴速率上限是硬约束。见 HARDWARE.md。软件只能检测和降级,不能突破机械。
  • 天极奇异:目标接近天极时所需 RA 速率发散。环会限幅并标记 degraded,但物理上追不上。
  • 赤道仪 vs 经纬仪:追快速移动目标,Alt-Az 其实是更合适的机构(没有场旋问题要另说, 但至少不会撞上赤经轴的奇异)。用赤道仪追飞机是"用手头的设备做难的事"。
  • 内置传播器是 J2 长期项 + 开普勒,精度公里级(见 propagate/kepler.py 文档字符串)。 要真追卫星请装 skyfield:pip install "skyhook[sat]"
  • LX200 脉冲模式有几角秒锯齿。
  • 图像闭环尚未内置:清晰度评价函数已有(focus/metrics.py),质心测量还没接。 目前 ADS-B/TLE 提供粗引导,精度受数据源限制。
  • 仿真相机的噪声模型是单像素高斯,没有建模热像素、坏列、读出噪声的非均匀性。 真机上建议给采样器加一点 blur_px 抑制热像素。

安全与法律

  • 永远不要把激光指向飞机或卫星。在多数国家这是刑事犯罪,且真的会伤到机组。
  • 在机场附近飞行/拍摄有额外法规;请遵守当地规定。
  • 拍摄航空器本身在绝大多数地区是合法的爱好(planespotting),但公开发布时注意隐私与当地法律。
  • 望远镜指向太阳会造成永久失明与设备损毁。本项目的仰角限制不是太阳安全保护, 别用它对着太阳。
  • 详情见 docs/SAFETY.md

路线图

  • 图像质心闭环(optical_fn),用相机精跟踪吃掉数据源误差
  • 多目标调度(一架落地自动切下一架)
  • 场旋补偿(Alt-Az + 消旋镜)
  • 完整 SGP4 内置实现(去掉 skyfield 依赖)
  • 过境预报 CLI(skyhook pass
  • Web 控制面板(目标列表、手动接管)

许可

MIT。见 LICENSE

About

Non-sidereal tracking and continuous autofocus for equatorial mounts - chase aircraft, satellites and anything that moves

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages