​Содержание:

 

  1. Введение
  2. Видеопрезентация работы
  3. Материалы и компоненты
  4. Шаг 1: Программный код (скетч)
  5. Шаг 2: Монтирование деталей
  6. Шаг 3: Установка корпуса
  7. Заключение


Введение:

Популярность автоматизированных домашних уборщиков с каждым днем возрастает. Не исключение, роботы-пылесосы для сухой уборки, способные поддерживать чистоту пола без вашего вмешательства. Принцип работы этих устройств очень прост и схож на прицип работы ручного пылесоса, главным отличием является наличие микроконтроллера, набора датчиков для самостоятельной работы, подзарядки и ориентировании в пространстве. Об этом мы ранее описывали в целой статье, специально посвященной роботизированным уборщикам полов.

Если вы хотите узнать, как он устроен и построить его собственными руками, представляем вашему вниманию инструкцию по сборке простейшего робота-пылесоса из подручных средств.




Видеопрезентация работы:



Материалы и компоненты:

Для создания робота-уборщика необходимы:

 

 

  • плата Arduino;
  • плата контроля электромоторов Arduino motor shield;
  • два двигателя с коробкой передач (3 вольта, приблизительно 100 оборотов в минуту);
  • два колеса или две алюминиевые банки;
  • турбина-кулер компьютерного охлаждения (5 В или 12 Вольт);
  • аккумулятор для питания 5 вольт;
  • пластина для сбора радиоэлементов и провода;
  • большой круглый пластиковый контейнер - для корпуса;
  • небольшой пластиковый контейнер - для мусоросборника;
  • картон;
  • термоклей;
  • магниты.






Шаг 1: Программный код и скетч:

Для правильной и точной работы в роботе-пылесосе существует "сердце" в виде микроконтроллера Arduino, программируемого с помощью домашнего ПК и необходимого программного обеспечения.

Скетч для работы робота-пылесоса загружается на плату с помощью программы Arduino IDE. Ниже программный код.







Программный код:


/*
Program for controlling a robot with two motors.
The robot turns when motors changes their speed and direction.
Front bumpers on left and right sides detect obstacles.
Ultrasonic sonars can be connected to analog inputs (tested on LV-MaxSonar-EZ1):
 - put pins in array sonarPins in following order: left, right, front, others..
   Examples: 
   1. only left and right sonars connected to pins 2 and 3:      sonarPins[] = {2,3}
   2. left, right and front sonars connected to pins 2, 3 and 5: sonarPins[] = {2,3,5}
   3. only front sonar connected to pin 5:                       sonarPins[] = {-1,-1,5}
   4. only left sonar connected to pin 2:                        sonarPins[] = {2}
   5. only right sonar connected to pins 3:                      sonarPins[] = {-1,3}
   6. 5 sonars connected to pins 1,2,3,4,5:                      sonarPins[] = {1,2,3,4,5}
Motor shield is used to run motors.
*/
const int Baud = 9600; //UART port speed

//Sonar properties
int sonarPins[] = {1, 2};//Analog Pin Nums to sonar sensor Pin AN
const long MinLeftDistance = 20; //Minimum allowed left distance
const long MinRightDistance = 20; //Minimum allowed right distance
const long MinFrontDistance = 15; //Minimum allowed front distance
const int SamplesAmount = 15;//more samples - smoother measurement and bigger lag
const int SonarDisplayFrequency = 10; //display only one of these lines - not all
int sonarDisplayFrequencyCount = 0;
const long Factor = 2.54 / 2;
long samples[sizeof(sonarPins)][SamplesAmount];
int sampleIndex[sizeof(sonarPins)];

//right side
const int pinRightMotorDirection = 4; //this can be marked on motor shield as "DIR A"
const int pinRightMotorSpeed = 3; //this can be marked on motor shield as "PWM A"
const int pinRightBumper = 2; //where the right bumper is connected

//left side
const int pinLeftMotorDirection = 7; //this can be marked on motor shield as "DIR B"
const int pinLeftMotorSpeed = 6; //this can be marked on motor shield as "PWM B"
const int pinLeftBumper = 8; //where the right bumper is connected

//uncomment next 2 lines if Motor Shield has breaks
//const int pinRightMotorBreak = PUT_BREAK_PIN_HERE; //this can be marked on motor shield as "BREAKE A"
//const int pinLeftMotorBreak = PUT_BREAK_PIN_HERE; //this can be marked on motor shield as "BREAKE B"

//fields
const int turnRightTimeout = 100;
const int turnLeftTimeout = 150;
//set in counter how long a motor is running back: N/10 (in milliseconds)
int countDownWhileMovingToRight;
int countDownWhileMovingToLeft;

//Initialization
void setup() {
  Serial.begin(Baud);
  initPins();

//uncomment next 4 lines if Motor Shield has breaks
//  pinMode(pinLeftMotorBreak, OUTPUT);
//  pinMode(pinRightMotorBreak, OUTPUT);
//  digitalWrite(pinLeftMotorBreak, LOW); //turn off breaks
//  digitalWrite(pinRightMotorBreak, LOW); //turn off breaks

  runRightMotorForward();
  runLeftMotorForward();
  startMotors();
}

//Main loop
void loop() {

  verifyAndSetRightSide();
  verifyAndSetLeftSide();

  processRightSide();
  processLeftSide();

  delay(10);//repeat every 10 milliseconds
}

//---------------------------------------------------
void initPins(){
  pinMode(pinRightMotorDirection, OUTPUT);
  pinMode(pinRightMotorSpeed, OUTPUT);
  pinMode(pinRightBumper, INPUT);
  pinMode(pinLeftMotorDirection, OUTPUT);
  pinMode(pinLeftMotorSpeed, OUTPUT);
  pinMode(pinLeftBumper, INPUT);
  for(int i = 0; i < sizeof(sonarPins); i++)
    pinMode(sonarPins[i], INPUT);
}

void startMotors(){
  setMotorSpeed(pinRightMotorSpeed, 255);
  setMotorSpeed(pinLeftMotorSpeed, 255);
}

void waitWhileAnyBumperIsPressed(){
  while(checkBumperIsNotPressed(pinRightBumper)
        && checkBumperIsNotPressed(pinLeftBumper)){
    delay(20);//check every 20 milliseconds
  }
}

void processRightSide(){
  if(countDownWhileMovingToRight <= 0)//checks if counter was NOT ran when bumper had been pressed
    return;
  //otherwise - counter is counting down (as a delay) while the right motor is moving backward
  countDownWhileMovingToRight--;//decrease the counter if it WAS ran when bumper had been pressed
  if(countDownWhileMovingToRight <= 0)//if the running counter got down to zero
    runRightMotorForward();//run the right motor forward
}

void processLeftSide(){
  if(countDownWhileMovingToLeft <= 0)
    return;
  countDownWhileMovingToLeft--;
  if(countDownWhileMovingToLeft <= 0)
    runLeftMotorForward();
}

void verifyAndSetRightSide(){
  if(checkBumperIsNotPressed(pinRightBumper)       //checks if right bumper has NOT been pressed
     && measureDistance(1, 'R') > MinRightDistance //checks if the minimum allowed right distance is not reached
     && measureDistance(2, 'F') > MinFrontDistance)//checks if the minimum allowed front distance is not reached
    return;
  if(checkCounterIsNotSet(countDownWhileMovingToRight))//if the counter is not yet counting down
    runRightMotorBackward();//run the right motor backward
  countDownWhileMovingToRight = turnRightTimeout;//set the counter to maximum value to start it counting down
}

void verifyAndSetLeftSide(){
  if(checkBumperIsNotPressed(pinLeftBumper)        //checks if left bumper has NOT been pressed
     && measureDistance(0, 'L') > MinLeftDistance  //checks if the minimum allowed left distance is not reached
     && measureDistance(2, 'F') > MinFrontDistance)//checks if the minimum allowed front distance is not reached
    return;
  if(checkCounterIsNotSet(countDownWhileMovingToLeft))//if the counter is not yet counting down
    runLeftMotorBackward();//run the right motor backward
  countDownWhileMovingToLeft = turnLeftTimeout;//set the counter to maximum value to start it counting down
}

bool checkCounterIsNotSet(int counter){
  return counter <= 0;
}

bool checkBumperIsNotPressed(int pinBumper){
  return digitalRead(pinBumper);
}

void runRightMotorForward(){
  runMotorForward(pinRightMotorDirection);
}

void runLeftMotorForward(){
  runMotorForward(pinLeftMotorDirection);
}

void runRightMotorBackward(){
  runMotorBackward(pinRightMotorDirection);
}

void runLeftMotorBackward(){
  runMotorBackward(pinLeftMotorDirection);
}

void runMotorForward(int pinMotorDirection){
  digitalWrite(pinMotorDirection, HIGH); //set direction forward
}

void runMotorBackward(int pinMotorDirection){
  digitalWrite(pinMotorDirection, LOW); //set direction backward
}

void setMotorSpeed(int pinMotorSpeed, int motorSpeed){
    analogWrite(pinMotorSpeed, motorSpeed);
}

//-- sonar methods --
long measureDistance(int pinIndex, char displayChar){
  if(!takeSample(pinIndex))
    return 255;//return large value when sonar is not connected
  long distance = calculateAvarageDistance(pinIndex) / Factor;
  printDistance(distance, displayChar);
  return distance;
}

void printDistance(long distance, char displayChar){
  if(--sonarDisplayFrequencyCount <= 0){
    sonarDisplayFrequencyCount = SonarDisplayFrequency;
    return;
  }

  Serial.print(distance);
  for(int i = 12; i < distance && i < 100; i += 2)
    Serial.print(displayChar);
  Serial.println();
}

boolean takeSample(int pinIndex){
  if(pinIndex >= sizeof(sonarPins) - 1 || sonarPins[pinIndex] < 0)//invalid pin index - pin is not defined
    return false;
  long value = analogRead(sonarPins[pinIndex]);
  if(value == 0)//pin is connected to GND - not to the sonar
    return false;
  if(++sampleIndex[pinIndex] >= SamplesAmount)
    sampleIndex[pinIndex] = 0;
  samples[pinIndex][sampleIndex[pinIndex]] = value;
  return true;
}

long calculateAvarageDistance(int pinIndex){
  long  average = 0;
  for(int i = 0; i < SamplesAmount; i++)
    average += samples[pinIndex][i];
  return average / SamplesAmount;
}
      

Шаг 2: Монтирование деталей:

Для крепления сервоприводов с колесами, кулера, плат управления, аккумулятора и другого используется картонная основа. Турбина и пластиковый контейнер (мусоросборник), с проделанным предварительно отверстием, прочно склеивается между собой и крепится на картон. Контейнер имеет отверстие для выдуваемого воздуха, на которое наклеена специальная синтетическая ткань, служащая фильтром.

Последовательно склеиваем кулер с сервоприводами, затем на сервоприводы клеим картонную площадку, на которой располагаются платы Arduino и батарея питания. Чтобы сделать колеса, необходимо отрезать нижнюю и верхнюю часть алюминиевых банок, склеить их между собой, а затем прочно закрепить на валу сервопривода.

В передней части монтируются металлические пластины (функция подвижного бампера), при замыкании которых сигнал поступает в плату управления электродвигателями Arduino motor shield, после чего сервоприводы начинают вращаться в другую сторону, изменяя направление движения робота.










Шаг 3: Установка корпуса:

При установке аккумуляторной батареи и подключении всех элементов конструкции с помощью проводов, необходимо обеспечить устройство прочным корпусом. Как раз таки для этого используется большой круглый контейнер. Для действия контактов, предотвращающих столкновение и застревание, делаем в контейнере специальные надрезы. Чтобы корпус был легкосъемным и прочно держался на механической части, используем восемь магнитов (при желании можно больше), по четыре приклеенных на самом контейнере и на внутренней части пылесоса соответственно.










Заключение:

Прекрасный прототип робота-пылесоса, сделанного своими руками. Не беря во внимание отсутствие дополнительных датчиков навигации и базы автоматической подзарядки, данный аппарат за пол часа работы вполне самостоятельно может собрать мусор, пыль и грязь на вашей кухне или в небольшой комнате. Его конструкция не представляет большой сложности, а стоимость и доступность деталей не вызывает сомнения. Все дело в творческом подходе. Вы можете менять элементы конструкции по вашему усмотрению, добавлять или убирать лишние элементы, модернизируя свой аппарат. Желаем приятно провести время, создавая свой робот для сухой уборки полов у вас дома.