Системы безопасности. Как не навредить людям и роботу
Робот — это машина с моторами, батареями и острыми краями. Он может ударить, прищемить, обжечь или даже загореться. Безопасность — это не “потом добавим”, а первое, о чём нужно думать при проектировании.
Три закона робототехники (Азимов, 1942)
- Робот не может причинить вред человеку или своим бездействием допустить, чтобы человеку был причинён вред.
- Робот должен повиноваться командам человека, кроме тех случаев, когда эти команды противоречат Первому Закону.
- Робот должен заботиться о своей безопасности, если это не противоречит Первому или Второму Законам.
В реальности: Эти законы — философия, а не код. Но они задают правильный образ мышления!
Уровни безопасности
Уровень 1: Механическая безопасность
Вопрос: Может ли робот физически навредить?
Уровень 2: Электрическая безопасность
Вопрос: Может ли робот ударить током или загореться?
Уровень 3: Программная безопасность
Вопрос: Может ли робот сделать что-то опасное из-за ошибки в коде?
Уровень 4: Поведенческая безопасность
Вопрос: Как робот ведёт себя в нештатных ситуациях?
1. Механическая безопасность
Кнопка аварийной остановки (E-Stop)
Требования:
- Большая, красная, заметная
- Физически отключает питание моторов (не через код!)
- Легко нажать, сложно случайно отжать (грибок)
Схема подключения:
[Батарея +] ─── [E-Stop] ─── [Драйвер моторов]
│
Нормально замкнут
При нажатии размыкает цепь
Важно: Кнопка должна разрывать силовую цепь, а не сигнальную!
НЕПРАВИЛЬНО: ПРАВИЛЬНО:
[Батарея] ─── [Драйвер] [Батарея] ─[E-Stop]─ [Драйвер]
│ │
[E-Stop на пине] [Моторы]
│
[Arduino]
Если Arduino зависнет, Физически разрывает питание,
кнопка не сработает! работает ВСЕГДА
Защитные кожухи и ограничители
Для манипуляторов:
Опасная зона:
┌─────────────────────────────────┐
│ │
│ [Манипулятор] │
│ │ │
│ ─────┴───── │
│ │
└─────────────────────────────────┘
↑ Ограждение по периметру
Безопасная зона для человека — снаружи!
Концевые выключатели:
// Физические ограничители на каждом суставе
void moveArm(int angle) {
// Программная проверка
if (angle < MIN_ANGLE || angle > MAX_ANGLE) {
return; // Не двигаться
}
// Но даже если код ошибётся...
// Концевики физически остановят движение!
motor.write(angle);
}
Скругление углов и мягкие бамперы
ОПАСНО: БЕЗОПАСНО:
┌────────────┐ ╭────────────╮
│ │ │ │
│ Робот │ │ Робот │
│ │ │ │
└────────────┘ ╰────────────╯
Острые углы Скруглённые углы
+ резиновые бамперы
2. Электрическая безопасность
Защита от короткого замыкания
// Предохранитель в силовой цепи
[Батарея +] ─── [Предохранитель 10A] ─── [Нагрузка]
// Или самовосстанавливающийся (PTC)
[Батарея +] ─── [Polyfuse] ─── [Нагрузка]
// При перегрузке нагревается и размыкает цепь
// После остывания — восстанавливается
Защита от переполюсовки
Диод в силовой цепи:
[Батарея +] ──▶|─── [Схема]
Диод Шоттки
Если батарею подключат наоборот — диод не пропустит ток
Изоляция высоковольтных цепей
Для роботов с моторами 12V+ и логикой 5V:
[Батарея 12V] [Arduino 5V]
│ │
[Драйвер моторов] [Логика]
│ │
└───[Оптопара]──────┘
Оптопара изолирует цепи друг от друга!
Безопасность Li-Po батарей
Правила хранения и использования:
✅ Хранить в огнеупорном пакете (LiPo Safe Bag)
✅ Заряжать только под присмотром
✅ Не заряжать повреждённые батареи
✅ Не разряжать ниже 3.2V на ячейку
✅ Не использовать вздутые батареи
❌ Не прокалывать, не сжимать
❌ Не оставлять на солнце
❌ Не хранить полностью заряженными
Что делать при возгорании:
1. НЕ тушить водой!
2. Вынести на улицу / балкон
3. Засыпать песком или накрыть огнеупорным одеялом
4. Дождаться полного прогорания
5. Проветрить помещение (токсичный дым!)
3. Программная безопасность
Ограничение скорости и ускорения
class SafeMotor {
private:
int currentSpeed = 0;
const int MAX_SPEED = 200; // Максимум 200 из 255
const int MAX_ACCELERATION = 10; // Макс. изменение за цикл
public:
void setSpeed(int target) {
// Ограничение максимальной скорости
target = constrain(target, -MAX_SPEED, MAX_SPEED);
// Плавное изменение скорости
if (target > currentSpeed) {
currentSpeed = min(currentSpeed + MAX_ACCELERATION, target);
} else {
currentSpeed = max(currentSpeed - MAX_ACCELERATION, target);
}
motor.write(currentSpeed);
}
};
Проверка “здравого смысла”
void processCommand(int speedLeft, int speedRight) {
// Проверка на разумность команды
// 1. Скорость в допустимых пределах?
if (abs(speedLeft) > 255 || abs(speedRight) > 255) {
logError("Недопустимая скорость!");
emergencyStop();
return;
}
// 2. Разница между моторами не слишком большая?
// (защита от резкого разворота)
if (abs(speedLeft - speedRight) > 100) {
logWarning("Слишком резкий поворот, сглаживаю");
// Сгладить разницу
}
// 3. Команда пришла недавно?
if (millis() - lastCommandTime > 500) {
logError("Потеря связи! Остановка.");
emergencyStop();
return;
}
// Только если все проверки пройдены
setMotors(speedLeft, speedRight);
}
Таймаут команд (Watchdog для связи)
unsigned long lastCommandTime = 0;
const unsigned long COMMAND_TIMEOUT = 500; // 500 мс
void loop() {
// Получение команды
if (commandReceived()) {
lastCommandTime = millis();
processCommand();
}
// Проверка таймаута
if (millis() - lastCommandTime > COMMAND_TIMEOUT) {
// Связь потеряна!
safeStop();
blinkErrorLED();
}
}
void safeStop() {
// Плавная остановка, не резкая!
while (currentSpeed > 0) {
currentSpeed -= 10;
setMotors(currentSpeed, currentSpeed);
delay(20);
}
}
4. Системы предотвращения столкновений
Зоны безопасности
const int ZONE_DANGER = 10; // см — экстренная остановка
const int ZONE_WARNING = 30; // см — снижение скорости
const int ZONE_CLEAR = 50; // см — нормальная работа
void checkCollision() {
int distance = readUltrasonic();
if (distance < ZONE_DANGER) {
// ОПАСНОСТЬ! Немедленная остановка
emergencyStop();
beepAlarm();
log(LOG_CRITICAL, "Объект слишком близко!");
}
else if (distance < ZONE_WARNING) {
// Предупреждение — снизить скорость
setSpeedLimit(50); // Максимум 50%
log(LOG_WARNING, "Объект в зоне предупреждения");
}
else {
// Всё чисто
setSpeedLimit(100);
}
}
Многосенсорная защита
struct SafetyStatus {
bool frontClear;
bool leftClear;
bool rightClear;
bool rearClear;
bool cliffDetected; // Обрыв (для мобильных роботов)
bool bumperPressed; // Физический контакт
};
SafetyStatus checkAllSensors() {
SafetyStatus s;
s.frontClear = (ultrasonicFront.read() > SAFE_DISTANCE);
s.leftClear = (ultrasonicLeft.read() > SAFE_DISTANCE);
s.rightClear = (ultrasonicRight.read() > SAFE_DISTANCE);
s.rearClear = (ultrasonicRear.read() > SAFE_DISTANCE);
s.cliffDetected = (irCliffSensor.read() < CLIFF_THRESHOLD);
s.bumperPressed = (digitalRead(BUMPER_PIN) == LOW);
return s;
}
void safeMove(int direction) {
SafetyStatus s = checkAllSensors();
// Нельзя ехать в направлении препятствия
if (direction == FORWARD && !s.frontClear) {
log(LOG_WARNING, "Блокировка: препятствие спереди");
return;
}
if (direction == BACKWARD && !s.rearClear) {
log(LOG_WARNING, "Блокировка: препятствие сзади");
return;
}
// Обрыв — экстренная остановка в любом случае!
if (s.cliffDetected) {
emergencyStop();
log(LOG_CRITICAL, "Обнаружен обрыв!");
return;
}
// Бампер — кто-то/что-то коснулось робота
if (s.bumperPressed) {
emergencyStop();
moveBackward(10); // Отъехать назад
log(LOG_WARNING, "Контакт с препятствием");
return;
}
// Все проверки пройдены — можно двигаться
executeMove(direction);
}
5. Безопасность на соревнованиях
Чек-лист перед стартом
Механика:
- Все винты затянуты
- Колёса не болтаются
- Провода не торчат наружу
- Острых краёв нет
Электрика:
- Батарея заряжена и не повреждена
- Предохранитель на месте
- E-Stop работает (проверить!)
- Нет оголённых проводов
Программа:
- Загружена ФИНАЛЬНАЯ версия
- Таймаут команд работает
- Ограничения скорости активны
- Логирование включено
Правила безопасности в пит-зоне
✅ Батареи хранить в LiPo-сумке
✅ Робота включать только на арене
✅ При работе с паяльником — очки!
✅ Держать огнетушитель под рукой
❌ Не оставлять включённого робота без присмотра
❌ Не заряжать батареи под столом
❌ Не запускать моторы при поднятом роботе
6. Примеры безопасных конструкций
Робот-доставщик (для коридора школы)
class DeliveryRobot {
private:
const int MAX_SPEED = 100; // Медленно!
const int PEOPLE_DISTANCE = 100; // 1 метр от людей
public:
void navigate() {
// Проверка всех направлений
if (detectPerson()) {
// Человек рядом — полная остановка
stop();
playSound("Пожалуйста, пропустите робота");
waitForClear();
}
// Медленное движение с постоянным сканированием
moveWithCaution();
}
bool detectPerson() {
// Используем несколько типов датчиков
bool lidar = lidarDetectsPerson();
bool pir = pirDetectsMotion();
bool camera = cameraDetectsPerson();
// Достаточно одного срабатывания
return lidar || pir || camera;
}
};
Манипулятор для учебного класса
class ClassroomArm {
private:
bool teacherOverride = false; // Учитель может отключить ограничения
public:
void setup() {
// Режим безопасности по умолчанию
setMaxSpeed(30); // Очень медленно
setMaxForce(1); // Минимальная сила
enableCollisionDetection(true);
}
void move(int x, int y, int z) {
// Ограничение рабочей зоны
if (!isInSafeZone(x, y, z)) {
log(LOG_WARNING, "Точка вне безопасной зоны");
return;
}
// Проверка на столкновение по пути
if (willCollide(x, y, z)) {
log(LOG_WARNING, "Обнаружено препятствие на пути");
return;
}
// Только учитель может снять ограничения
if (!teacherOverride) {
x = constrain(x, SAFE_X_MIN, SAFE_X_MAX);
y = constrain(y, SAFE_Y_MIN, SAFE_Y_MAX);
z = constrain(z, SAFE_Z_MIN, SAFE_Z_MAX);
}
executeMove(x, y, z);
}
};
Проверь своего робота
Вопросы безопасности:
- Что случится, если программа зависнет?
- Что случится, если пропадёт связь с пультом?
- Может ли робот поранить человека при максимальной скорости?
- Что случится, если перепутать полярность батареи?
- Есть ли способ НЕМЕДЛЕННО остановить робота?
Если на все вопросы есть хорошие ответы — ваш робот безопасен!
Что дальше?
- Отказоустойчивость — как сделать робота надёжным
- Watchdog и избыточность — резервные системы
- Мониторинг питания — контроль состояния батареи
