У вас трактор. Может быть — комбайн, опрыскиватель, КамАЗ. Утром он уехал в поле. Вечером — вернулся. Вопрос: где он был? Сколько проехал? Сколько топлива сжёг? Ответ на большинстве хозяйств: «Ну, вроде на четвёртом поле работал. Наверное. Топлива списали 80 литров — бригадир сказал, что столько залили.»
Промышленные GPS-трекеры для сельхозтехники стоят от 15 до 50 тысяч рублей за единицу плюс абонентская плата. На парк из 10 единиц — минимум 150 тысяч. Мы соберём GPS-трекер за 2 500 ₽, который покажет маршрут, скорость, остановки — и отправит всё в Google Таблицу.
Компоненты: что покупаем
- ESP32 DevKit v1 — 450 ₽ (Wi-Fi + Bluetooth, 2 ядра, 240 МГц)
- NEO-6M GPS-модуль — 350 ₽ (с внешней керамической антенной, точность 2,5 м CEP)
- SIM800L GSM-модуль — 450 ₽ (2G GPRS, отправка данных через мобильную сеть)
- SIM-карта — МТС IoT тариф: 50 ₽/мес (10 МБ, для GPS-трекера более чем достаточно)
- DC-DC преобразователь LM2596 — 80 ₽ (питание от бортсети 12/24V)
- Корпус IP65 — 200 ₽ (пылевлагозащита для установки на технике)
- Провода, разъёмы, термоусадка — 120 ₽
- Внешняя GPS-антенна на магните — 250 ₽ (крепится на крышу кабины)
Итого: ~1 950 ₽ за один трекер. С запасом на доставку и мелочи — 2 500 ₽.
Схема подключения
ESP32 — мозг. К нему подключены два модуля:
- NEO-6M (GPS) → UART2: TX на GPIO16, RX на GPIO17
- SIM800L (GSM) → UART1: TX на GPIO26, RX на GPIO27
- Питание ESP32: 5V от LM2596 (вход 12–24V от бортсети)
- Питание SIM800L: отдельный выход LM2596 на 4.0V (модуль капризный к напряжению!)
- NEO-6M: питание 3.3V от ESP32
Критично для SIM800L: этот модуль при передаче данных потребляет пиковые 2A. Стандартного USB-питания не хватит — нужен LM2596 с конденсатором 1000 мкФ на выходе. Без этого модуль будет перезагружаться при каждой отправке.
Код прошивки: полная версия
#include <TinyGPS++.h>
#include <HardwareSerial.h>
// GPS на UART2
HardwareSerial gpsSerial(2);
TinyGPSPlus gps;
// SIM800L на UART1
HardwareSerial simSerial(1);
// Настройки
const char* APN = "internet.mts.ru";
const char* SERVER = "script.google.com"; // Google Apps Script
const char* SCRIPT_ID = "ВАШ_SCRIPT_ID";
const unsigned long SEND_INTERVAL = 60000; // отправка каждые 60 сек
const float SPEED_THRESHOLD = 3.0; // км/ч — ниже = стоянка
unsigned long lastSend = 0;
float totalDistance = 0;
double prevLat = 0, prevLng = 0;
bool engineOn = false;
void setup() {
Serial.begin(115200);
gpsSerial.begin(9600, SERIAL_8N1, 16, 17);
simSerial.begin(9600, SERIAL_8N1, 16, 17); // пины 26, 27
// Исправление: SIM800L на своих пинах
simSerial.end();
simSerial.begin(9600, SERIAL_8N1, 27, 26);
delay(3000); // ждём инициализацию SIM800L
initSIM800();
Serial.println("GPS Tracker started");
}
void loop() {
// Читаем GPS
while (gpsSerial.available()) {
gps.encode(gpsSerial.read());
}
if (gps.location.isValid() &&
millis() - lastSend > SEND_INTERVAL) {
float speed = gps.speed.kmph();
double lat = gps.location.lat();
double lng = gps.location.lng();
// Считаем пробег
if (prevLat != 0) {
totalDistance += TinyGPSPlus::distanceBetween(
prevLat, prevLng, lat, lng) / 1000.0;
}
prevLat = lat;
prevLng = lng;
// Определяем состояние
String state = speed > SPEED_THRESHOLD ? "moving" : "stopped";
// Отправляем данные
sendData(lat, lng, speed, totalDistance, state);
lastSend = millis();
Serial.printf("Lat: %.6f, Lng: %.6f, Speed: %.1f, Dist: %.2f\n",
lat, lng, speed, totalDistance);
}
}
void initSIM800() {
sendAT("AT", "OK", 1000);
sendAT("AT+CPIN?", "READY", 5000);
sendAT("AT+CREG?", "0,1", 10000);
sendAT("AT+CGATT=1", "OK", 10000);
sendAT("AT+CIPSHUT", "SHUT OK", 5000);
sendAT("AT+CIPMUX=0", "OK", 1000);
String apnCmd = "AT+CSTT=\"" + String(APN) + "\"";
sendAT(apnCmd.c_str(), "OK", 5000);
sendAT("AT+CIICR", "OK", 10000);
sendAT("AT+CIFSR", ".", 5000);
}
void sendData(double lat, double lng, float speed,
float dist, String state) {
String url = "/macros/s/" + String(SCRIPT_ID) + "/exec";
url += "?lat=" + String(lat, 6);
url += "&lng=" + String(lng, 6);
url += "&speed=" + String(speed, 1);
url += "&dist=" + String(dist, 2);
url += "&state=" + state;
String cmd = "AT+CIPSTART=\"TCP\",\"" +
String(SERVER) + "\",80";
if (!sendAT(cmd.c_str(), "CONNECT OK", 15000)) {
sendAT("AT+CIPSHUT", "SHUT OK", 3000);
return;
}
String http = "GET " + url + " HTTP/1.1\r\n";
http += "Host: " + String(SERVER) + "\r\n\r\n";
String cipSend = "AT+CIPSEND=" + String(http.length());
sendAT(cipSend.c_str(), ">", 5000);
simSerial.print(http);
delay(5000);
sendAT("AT+CIPCLOSE", "CLOSE OK", 3000);
}
bool sendAT(const char* cmd, const char* expected,
unsigned long timeout) {
simSerial.println(cmd);
unsigned long start = millis();
String response = "";
while (millis() - start < timeout) {
if (simSerial.available()) {
response += (char)simSerial.read();
if (response.indexOf(expected) != -1) return true;
}
}
Serial.println("AT fail: " + String(cmd));
return false;
}
Google Apps Script: приёмник данных
Создаём Google Таблицу, открываем Apps Script (Расширения → Apps Script), вставляем:
function doGet(e) {
var sheet = SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("GPS");
if (!sheet) {
sheet = SpreadsheetApp.getActiveSpreadsheet()
.insertSheet("GPS");
sheet.appendRow(["Время", "Широта", "Долгота",
"Скорость км/ч", "Пробег км",
"Состояние"]);
}
sheet.appendRow([
new Date(),
e.parameter.lat,
e.parameter.lng,
e.parameter.speed,
e.parameter.dist,
e.parameter.state
]);
return ContentService
.createTextOutput("OK")
.setMimeType(ContentService.MimeType.TEXT);
}
Публикуем: Развернуть → Новое развёртывание → Тип: Веб-приложение → Доступ: Все. Копируем ID скрипта — вставляем в прошивку ESP32.
Установка на технику
Корпус IP65 крепим под капотом или в кабине на двусторонний скотч 3M VHB (держит вибрацию). GPS-антенна — на крышу кабины на магните, кабель через уплотнитель двери. Питание — от клеммы ACC (зажигание) через предохранитель 1A.
Почему от ACC, а не от постоянного плюса: чтобы трекер работал только при включённом зажигании. Это и экономит SIM-трафик, и показывает реальное время работы техники. Если нужен режим охраны (трекер работает всегда) — подключайте к постоянному плюсу и добавьте в код режим сна с пробуждением по акселерометру (ADXL345, +80 ₽).
Герметизация: все соединения — пайка + термоусадка. Никаких скруток и изоленты — вибрация на тракторе разболтает за неделю. Вход кабеля GPS-антенны в корпус — через PG-гланд или силиконовый герметик.
Что видим в таблице
Каждую минуту (или чаще — настраивается) в таблицу приходит строка: время, координаты, скорость, пробег, состояние. Из этих данных извлекаем:
Маршрут за день. Копируем столбцы «Широта» и «Долгота» в Google Maps (или My Maps) — видим трек. Трактор действительно был на четвёртом поле? Или катался в деревню?
Время работы vs. простоя. Строки со «stopped» — техника стоит. Считаем: out of 8 часов смены — 3 часа простоя. Разбираемся.
Расход топлива (косвенный). Если знать средний расход трактора на 100 км (например, 25 л/100 км для МТЗ-82), то пробег × расход = ожидаемый расход. Сравниваем с заправленным — если разница больше 15%, кто-то сливает.
Геозоны. В Google Sheets добавляем формулу: если координаты выходят за границы хозяйства — выделяем красным. Трактор уехал за пределы — мгновенно видно.
Продвинутая версия: MQTT + дашборд
Google Таблица — хороший старт, но для 5+ единиц техники нужен нормальный дашборд. Вариант без затрат:
- MQTT-брокер: бесплатный HiveMQ Cloud (до 100 подключений)
- Node-RED: визуальный ETL на Raspberry Pi или VPS (бесплатный)
- Grafana: дашборд с картой, графиками скорости, пробега (бесплатный)
ESP32 отправляет данные в MQTT-топик farm/tracker/tractor1. Node-RED подписывается, записывает в InfluxDB. Grafana рисует карту с трекингом в реальном времени. Шеф открывает дашборд с телефона — видит, где вся техника прямо сейчас.
Настройка MQTT-версии — отдельный проект на выходные, но ESP32 код меняется минимально: вместо HTTP GET на Google Apps Script — MQTT publish через библиотеку PubSubClient.
Расход SIM-трафика и автономность
Один HTTP GET запрос с координатами — ~200 байт. При отправке раз в минуту за 10-часовую смену: 200 × 600 = 120 КБ. За месяц (25 рабочих дней): 3 МБ. Тариф МТС IoT с 10 МБ — хватает с запасом на 3 единицы техники.
Питание от бортсети — автономность неограничена (пока работает двигатель). Потребление ESP32 + GPS + GSM в активном режиме — ~150–200 мА при 5V. От бортовых 12V через LM2596 — копейки на фоне расхода техники.
Если нужна работа при выключенном зажигании (режим охраны): добавляем аккумулятор 18650 (3.7V, 3400 мАч) + модуль зарядки TP4056. В режиме сна ESP32 потребляет 10 мкА — хватит на месяцы. Пробуждение по сигналу акселерометра: техника поехала → трекер проснулся → отправил координаты.
Три сценария, где трекер окупается за неделю
Сценарий 1: Слив топлива. Трактор МТЗ-82 расходует ~25 л/100 км. По GPS пробег за день — 40 км. Ожидаемый расход: 10 литров. Списано: 25 литров. Разница — 15 литров × 65 ₽ = 975 ₽/день. За месяц — 24 000 ₽. Трекер за 2 500 ₽ окупился за 3 дня.
Сценарий 2: «Левые» рейсы. КамАЗ с зерном должен ехать на элеватор (15 км). По GPS — заехал куда-то на 30 минут, потом на элеватор. Куда заезжал? Может, отсыпал кому-то пару тонн? При цене пшеницы 15 000 ₽/т — 2 тонны = 30 000 ₽. Один такой рейс — и трекер окупил себя 12 раз.
Сценарий 3: Простои. По GPS видно: трактор работал 4 часа из 10 (6 часов — «stopped»). Разговор с трактористом: «Ждал подвоз семян 2 часа, потом обед, потом гроза». Факт зафиксирован — можно оптимизировать логистику подвоза. +20% эффективности парка — это серьёзные деньги.
Юридический момент
GPS-мониторинг служебного транспорта — законен. ТК РФ позволяет работодателю контролировать использование служебного имущества. Но: сотрудники должны быть уведомлены (пункт в трудовом договоре или приказ). Скрытое слежение за личным транспортом — нарушение (ст. 137 УК РФ). Наш случай — техника принадлежит хозяйству, работники уведомлены — всё законно.
Типичные проблемы и решения
- GPS не находит спутники: антенна должна «видеть небо». Под металлической крышей — не работает. Вынесите антенну наружу на магните.
- SIM800L перезагружается: недостаточное питание. Добавьте конденсатор 1000 мкФ на линию питания модуля.
- Данные не приходят в таблицу: проверьте APN (internet.mts.ru для МТС, internet для МегаФон, internet.beeline.ru для Билайн). Проверьте баланс SIM-карты.
- Координаты «прыгают»: включите фильтр в коде — игнорировать точки с HDOP > 5 (
gps.hdop.hdop() < 5.0). - Модуль не подключается к сети: SIM800L работает только в 2G. Убедитесь, что оператор поддерживает 2G в вашем регионе. Альтернатива — SIM7600 (4G, ~1 200 ₽).
Альтернатива: готовые платы с GPS + GSM
Если не хотите паять три модуля — есть готовые решения:
- TTGO T-Call (SIM800L + ESP32 на одной плате) — ~900 ₽. Добавляете только GPS-модуль.
- LILYGO T-SIM7600 — ~2 500 ₽. ESP32 + 4G + GPS на одной плате. Подключил — работает. Дороже, но никакой пайки и проблем с питанием SIM800L.
Для тех, кто использует платформы вроде ТерраКвант, есть готовые интеграции с GPS-трекерами — данные с самодельных устройств можно подключить через API.
Прошивка по воздуху: OTA-обновление
Трекер установлен на комбайне, комбайн уехал на дальнее поле. Вы нашли баг в коде или хотите изменить интервал отправки. Снимать ESP32 и тащить к компьютеру? Нет — настроим OTA (Over-The-Air) обновление.
ESP32 поддерживает OTA «из коробки» через библиотеку ArduinoOTA. Но для трекера в поле без Wi-Fi удобнее HTTP OTA: прошивка скачивается с сервера при подключении к мобильной сети. Добавьте в код:
// Проверка обновлений раз в сутки
const unsigned long OTA_CHECK_INTERVAL = 86400000;
unsigned long lastOTACheck = 0;
const char* FW_URL =
"http://ваш-сервер.ru/firmware/tracker.bin";
void checkOTA() {
if (millis() - lastOTACheck < OTA_CHECK_INTERVAL)
return;
lastOTACheck = millis();
// Через SIM800L скачиваем HTTP заголовок
// Сравниваем версию — если новее, скачиваем .bin
// ESP32 перезаписывает прошивку и перезагружается
Serial.println("OTA check...");
// Реализация через httpUpdate библиотеку
}
Полная реализация HTTP OTA через SIM800L — около 50 строк дополнительного кода. Зато вы можете обновить все 10 трекеров одновременно, выложив новую прошивку на сервер. Экономия: десятки часов беготни по технике.
Геозоны: автоматические уведомления
Геозона — виртуальная граница на карте. Техника пересекла границу → вам приходит уведомление. Применения:
- Граница хозяйства: трактор выехал за пределы → Telegram: «⚠️ МТЗ-82 покинул территорию хозяйства, 14:32»
- Запретные зоны: техника заехала на засеянное поле, где ей нечего делать → уведомление
- Контрольные точки: КамАЗ доехал до элеватора → автоматическая отметка «доставлено»
Реализация в Google Apps Script:
// Геозона — прямоугольник
var FENCE = {
latMin: 51.500, latMax: 51.520,
lngMin: 45.100, lngMax: 45.130
};
function checkGeofence(lat, lng) {
lat = parseFloat(lat);
lng = parseFloat(lng);
if (lat < FENCE.latMin || lat > FENCE.latMax ||
lng < FENCE.lngMin || lng > FENCE.lngMax) {
sendTelegramAlert(
"Техника покинула территорию! " +
lat + ", " + lng
);
}
}
function sendTelegramAlert(text) {
var token = "ВАШ_BOT_TOKEN";
var chatId = "ВАШ_CHAT_ID";
var url = "https://api.telegram.org/bot" + token +
"/sendMessage?chat_id=" + chatId +
"&text=" + encodeURIComponent(text);
UrlFetchApp.fetch(url);
}
Добавляете вызов checkGeofence() в функцию doGet() — и при каждом получении координат проверяется геозона. Для нескольких техник — добавьте параметр id в URL трекера, чтобы различать устройства.
Реальная экономика: расчёт для хозяйства 1 000 га
Типичный парк: 3 трактора, 1 комбайн, 2 грузовика. Итого 6 единиц.
Затраты:
- 6 трекеров × 2 500 ₽ = 15 000 ₽
- SIM-карты: 6 × 50 ₽/мес × 12 = 3 600 ₽/год
- Установка: 1 день работы (свой электрик)
- Итого за первый год: ~18 600 ₽
Экономия (консервативная оценка):
- Снижение слива топлива: 5 л/день × 25 дней × 6 мес × 65 ₽ = 48 750 ₽
- Оптимизация простоев (+15% использования парка): эквивалент снижения затрат на ~30 000 ₽/сезон
- Предотвращение «левых» рейсов: 1 случай × 30 000 ₽ = 30 000 ₽
- Итого: ~108 000 ₽/сезон
ROI: 108 000 / 18 600 = 5.8x за первый год. Даже если половина экономии — фантазия, 3x окупаемость — реальность.
Логирование на SD-карту: страховка от потери связи
Мобильная сеть в полях бывает нестабильной. Если SIM800L не смог отправить данные — координаты теряются. Решение: параллельная запись на microSD-карту. ESP32 поддерживает SD через SPI, модуль microSD — 60 ₽.
#include <SD.h>
#include <SPI.h>
const int SD_CS = 5; // Chip Select на GPIO5
void logToSD(double lat, double lng, float speed,
float dist, String state) {
File f = SD.open("/gps_log.csv", FILE_APPEND);
if (f) {
f.printf("%lu,%.6f,%.6f,%.1f,%.2f,%s\n",
millis(), lat, lng, speed, dist, state.c_str());
f.close();
}
}
Карта на 4 ГБ вмещает ~50 миллионов записей — это годы работы. Раз в неделю вытаскиваете карту (или подключаетесь по Wi-Fi на базе) и выгружаете данные. Даже если GSM не работал всю неделю — ни одна точка не потеряна.
Продвинутый вариант: ESP32 при появлении связи автоматически отправляет накопленные на SD данные пакетом. Чуть сложнее в коде, но полностью автоматизирует процесс.
Альтернатива для тех, кто не паяет: ESP32 + смартфон
Совсем бюджетный вариант без SIM800L и GPS-модуля: старый Android-смартфон. Устанавливаете приложение GPS Logger (бесплатное), настраиваете автозагрузку координат в Google Таблицу. Смартфон крепите в кабине, подключаете к зарядке от прикуривателя. Стоимость: 0 ₽ (если есть старый телефон).
Минусы: смартфон менее надёжен (перегрев, андроид убивает фоновые приложения, экран выгорает на солнце), но как proof of concept для одного трактора — работает. Убедились в пользе — переходите на ESP32.
В следующей статье — приёмка урожая: как тонны теряются между полем и складом, и почему весы на КПП не решают проблему.




