Skip to main content

Системы безопасности. Как не навредить людям и роботу

Робот — это машина с моторами, батареями и острыми краями. Он может ударить, прищемить, обжечь или даже загореться. Безопасность — это не “потом добавим”, а первое, о чём нужно думать при проектировании.


Три закона робототехники (Азимов, 1942)

  1. Робот не может причинить вред человеку или своим бездействием допустить, чтобы человеку был причинён вред.
  2. Робот должен повиноваться командам человека, кроме тех случаев, когда эти команды противоречат Первому Закону.
  3. Робот должен заботиться о своей безопасности, если это не противоречит Первому или Второму Законам.

В реальности: Эти законы — философия, а не код. Но они задают правильный образ мышления!


Уровни безопасности

Уровень 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);
  }
};

Проверь своего робота

Вопросы безопасности:

  1. Что случится, если программа зависнет?
  2. Что случится, если пропадёт связь с пультом?
  3. Может ли робот поранить человека при максимальной скорости?
  4. Что случится, если перепутать полярность батареи?
  5. Есть ли способ НЕМЕДЛЕННО остановить робота?

Если на все вопросы есть хорошие ответы — ваш робот безопасен!


Что дальше?