Как ошибка в измерения погубила Mars Climate Orbiter?
Как ошибка в измерения погубила Mars Climate Orbiter?
23 сентября 1999 года аппарат Mars Climate Orbiter должен был выйти на орбиту Марса. Он почти девять месяцев летел к планете, передавал данные и выполнял команды. Затем начался манёвр торможения…
Расследование показало неприятную причину. Один программный модуль передавал данные в английской системе единиц, а другой считал, что получает их в метрической. Числа выглядели вполне нормально. Только означали совсем не то.
Аппарат прошёл примерно на 170 километров ниже запланированной траектории. Скорее всего, он разрушился в атмосфере Марса. Миссия стоимостью более 300 миллионов долларов закончилась из-за ошибки, которую на Земле исправили бы одной конвертацией.
Не совсем миллиметры против дюймов
Историю часто пересказывают как путаницу между метрами и футами или миллиметрами и дюймами. Так звучит проще, но реальная ошибка была немного интереснее.
Наземная программа компании Lockheed Martin записывала импульс двигателей в lbf·s — фунт-секундах. Навигационное программное обеспечение NASA ожидало получить N·s — ньютон-секунды.
Разница между ними — примерно в 4,45 раза. Когда одна система отправляла значение 10, другая читала его не как 10 фунт-секунд, а как 10 ньютон-секунд. Формат файла подходил, число успешно загружалось, программа не падала. Ошибка спокойно продолжала жить.
Почему компьютер ничего не заметил
Для программы единица измерения часто существует лишь в документации. Переменная типа float не знает, что именно в ней хранится: метры, секунды, доллары или температура духовки.
Упрощённо проблемная граница между системами выглядела так:
def update_trajectory(impulse): spacecraft.velocity += impulse / spacecraft.mass
Функция получает число и выполняет расчёт. Передать ей значение в неправильных единицах можно без единого предупреждения. С точки зрения языка программирования всё корректно.
Именно поэтому ошибки в единицах так коварны. Неверный пароль быстро даст отказ. Отсутствующий файл вызовет исключение. А правдоподобное число пройдёт через десятки функций и лишь постепенно испортит результат.
Ошибка накапливалась девять месяцев
Mars Climate Orbiter не свернул к Марсу резко. После небольших включений двигателей навигационная команда пересчитывала траекторию. Каждый раз расчёт получал немного неправильные данные.

Особенно заметной проблема стала из-за частых операций по разгрузке маховиков ориентации. Их проводили чаще, чем ожидалось, а значит, неверные значения импульса поступали в расчёты снова и снова.
Отклонение росло постепенно. Некоторые специалисты замечали, что расчётная траектория ведёт аппарат слишком низко, но проблема не была вовремя доведена до полноценного расследования. Это уже не история об одной забытой формуле. Это цепочка слабых проверок и неудачной коммуникации.
Почему тесты не спасли миссию
Техническое требование было правильным: данные следовало передавать в метрической системе. Ошибка находилась в реализации одного компонента и не была обнаружена на границе с другим.
Каждая программа могла корректно работать отдельно. Одна честно сохраняла свои значения, другая правильно обрабатывала полученные числа. Ломалась связка между ними — та самая область, которую модульные тесты часто обходят стороной.
Здесь нужен был простой сквозной тест: создать известный импульс в исходной программе, передать файл навигационной системе и проверить получившееся изменение скорости. Такой тест обнаружил бы расхождение почти сразу.
Как не повторить эту ошибку в обычном проекте
Космические аппараты запускают не все, но похожие ошибки встречаются постоянно. Backend возвращает время в секундах, frontend принимает его за миллисекунды. Один сервис хранит цену в долларах, другой ожидает центы. В базе температура записана в градусах Цельсия, а внешнее API присылает Фаренгейты.
Минимальная защита — указывать единицу прямо в имени: timeout_ms, price_cents, impulse_ns. Конвертацию лучше выполнять в одном заметном месте, а не разбрасывать загадочные множители по проекту.
def lbf_seconds_to_newton_seconds(value): return value * 4.4482216153 impulse_ns = lbf_seconds_to_newton_seconds(impulse_lbf_s) apply_impulse(impulse_ns)
В критических системах стоит идти дальше: использовать отдельные типы для разных величин и запрещать их случайное смешивание. А на границах сервисов проверять не только формат данных, но и допустимый диапазон. Если значение формально корректно, однако физически странно, система должна хотя бы поднять тревогу.
Ошибка была маленькой только в коде
История Mars Climate Orbiter удобна тем, что в ней нет сложной загадки. Не потребовались неизвестный аппаратный дефект или редкое космическое явление. Две команды просто по-разному понимали смысл одного числа.
Но свести катастрофу к невнимательности одного программиста было бы слишком легко. Проект потеряли потому, что несоответствие прошло через спецификацию, разработку, тестирование и контроль траектории.
Похожие записи
Оцените материал:
Похожие записи
Юридическая фирма по искусственному интеллекту Crosby делает ставку на распадающуюся знаменитую фирму Weil Gotshal
31.10.2026
Как исследовательский проект Массачусетского технологического института превратился в глобальный язык программирования
30.10.2026Присоединяйтесь и подпишитесь на рассылку самых свежих новостей по Email
Получайте свежие новости и идеи на почту. Без спама — только самое интересное.
Нажимая «Подписаться», вы соглашаетесь с политикой конфиденциальности.
