Category: Проекты

December 10, 2019 siteprovisor No comments exist

Строим самолёт

Раз уж вы решились на такое трудоёмкое и местами кропотливое дело, как постройка самолёта – успеха!

 

Можно использовать

Материалы и инструменты

Обшивки самолета – полипропиленовая подложка под ламинат толщиной около 3 мм. Для крыла подойдет гибкая с продольными полосами. Линейки 50 см для лонжерона крыла и продольного усиления фюзеляжа. Фанерка для моторамы и резинка портновская (не менее 1 см шириной) для крепления съёмного крыла. Плита утеплителя ППЭ для элементов усиления фюзеляжа.

 

 

Понадобятся: металлическая линейка, нож (лучше специальный), клей для потолочной плитки “Титан”, скотч, армирующая лента “серпянка”, малярная лента, термоклеевой пистолет и стержни, мелкая шкурка, зажимы, клей ПВА.

Хвостовое оперение

Сборка хвостового оперения - киль и стабилизатор

Сборка фюзеляжа

Фюзеляж - Борт

Фюзеляж - Установка усилений

Дополнительные элемента усиления фюзеляжа

Сборка фюзеляжа

Фюзеляж - установка верхней и нижней обшивок

Крыло

Установка лонжерона и нервюр

Установка серв и склейка обшивки

Навеска элеронов

Установка оперения и моторамы

Конструкция планера в сборе

Балансировка

Собрав фюзеляж, оснастив его всем оборудованием, установив крыло – необходимо провести балансировку самолёта.

Центр масс полностью собранного и укомплектованного самолёта должен приходиться на линию, отстоящую от передней кромки крыла на 1/3 ширины крыла. Линию прочертить заранее. Поставить большие пальцы на линию, поднять – самолёт должен уверенно лежать и никуда не крениться.

Можно лететь!

October 12, 2019 siteprovisor No comments exist

Программируем по настоящему. Загадочные регистры

Немного о том, что знают настоящие не “ардуино-зависимые” программисты о микроконтроллерах

И еще о том, зачем в школе мучают булевой алгеброй

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

Но в микроконтроллере есть ещё и другие регистры – хранящие настройки разных периферийных устройств (портов ввода/вывода, например). С ними в основном и имеет дело программист. Например регистр PORTB, хранящий состояние выводов (пинов), или регистр DDR, хранящий настройки, находятся ли выводы (пины) в состояние входа или выхода.

 

Конфигурировать регистры будем булевыми операциями – AND (&) и OR(|).

Ну, говорить о том, что представлять содержание регистра удобнее всего в шестнадцатеричной или двоичной системе не будем.

Также умолчим о возможности калькулятора (вид->инженерный) переводить числа между разными системами

.

Вот таблица истинности – правила двоичной арифметики, ну это уж почти всем известно

Ну раз регистр это просто ячейка, например, из 8 бит, то выставим в регистре с именем PORTB восемь единичек:

Или все нули:

А теперь, как выставить 1 в первом бите (обратите внимание на нумерацию битов в регистре – начинается 0), не изменив состояние других – при помощи OR (операция выполняется побитово):

Как же выставить 0 в любом бите – при помощи AND

Выставляем 0 в первом бите, не изменив состояние других – при помощи AND (операция выполняется побитово):

Вот целый курс по программированию МК AVR “правильно” таким hard core способом, который в общем то и используют настоящие разработчики (customelectronics.ru)

Зажжем диод на ардуино, заодно попрактикуемся с регистрами.

Заглянув в datasheet на микроконтроллер ATmega8 семейства AVR (да, да, именно такой и в вашей ардуине), в ужасе ничего не понимаешь понимаешь, что выходы соответствуют трем портам B, C, D – PB0-5, PC0-5, PD0-7. В Arduino эти названия переименованы в цифровые выводы D0-D13 и аналоговые входы A0-A5.

Выводы управляются регистрами PORTх и DDRх.

Например, вывод PB5 управляется пятым битом в регистрах PORTB (состояние вывода – 0 или 1, 0В или 5В) и DDRB (настройка вывода – на вход(0) и выход(1));

Итак, чтобы подать 1 (5В) на 13 пин ардуино (PB5):

Вот так просто

July 11, 2019 finereader No comments exist

Робот манипулятор. Собираем готовый проект

 

Программная часть готового проекта :

  • код для платы Arduino, получающей по COM-порту от компьютера пакет с тремя углами поворота серводвигателей
  • программа в среде Processing, работающая на ПК, которая сначала определяет координаты мишени (обрабатывая изображение с камеры), а затем рассчитывает углы для Arduino

 

 

Только для начала, было бы неплохо отработать всю систему без камеры, просто указывая координаты мышкой на экране. Для этого и предназначена вот эта программа для Processing. Работает с той же программой для Arduino.

July 11, 2019 finereader No comments exist

Робот манипулятор. Техническое зрение

В нашем проекте по созданию робота мы уже разработали кинематику движения, конструкцию звеньев и алгоритм движения.

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

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

Повесим веб-камеру над рабочей зоной, в Processing захватим видео с этой камеры.

Обработка в Processing будет представлять чтение изображения с камеры несколько раз в секунду, а затем выделения пикселей требуемого цвета. Найдя все подходящие пиксели, зная их координаты, определим “центр масс” всей фигуры – это и есть точка, целеуказание для робота.


/*Программа реализует захват изображения 
с камеры и определение объекта цветовым фильтром
в пространстве HSB (в нем намного удобнее сравнивать объекты,
чем в RGB-пространстве)
Выбор цвета для работы фильтра производится указанием
мыши на пиксель*/

import processing.video.*;

Capture cam;
   
   //Переменные для хранения выбранного цвета
   float huesel = 0.0; //Оттенок цвета
   float satsel = 0.0;
   float brsel = 0.0;
  
  //Переменные для расчета центра фигуры
  int ii=0; //счетчик найденных пикселей
  float sumX=0.0; //сумма Х-координат найденных пикселей выбранного цвета
  float sumY=0.0; //сумма Y-координат найденных пикселей выбранного цвета

int w=320; //640
int h=240; //480

void setup() {
  
  size(320, 240);
  //size(640, 480);
  String[] cameras = Capture.list();

  if (cameras == null) {
    println("Failed to retrieve the list of available cameras, will try the default...");
    cam = new Capture(this, w, h);
  } if (cameras.length == 0) {
    println("There are no cameras available for capture.");
    exit();
  } else {
    println("Available cameras:");
    printArray(cameras);
    
    //Интерфейс камеры с нужным разрешением(320х240)
   // cam = new Capture(this, cameras[9]);
    cam = new Capture(this, cameras[12]);
    cam.start();
  }
}

void draw() {
  //Захватываем изображение с камеры
  if (cam.available() == true) {
    cam.read();
  }
  
  //Выводим изображение в окно
  image(cam, 0, 0, width, height);
  
  //Пробегаем по всем пикселям изображения
  ii=0; sumX=0.0; sumY=0.0;
  for (int i=0;i<w;i+=1){
    for(int j=0; j<h;j+=1){
       //получаем цвет текущего пикселя
       color cc = get(i,j);
       //и переводим его в HSB-пространство
       float h = hue(cc);
       float s = saturation(cc);
       float br = brightness(cc);
       //Сравниваем тек. пиксель с выбранным с учетом 
       //некоторого допуска на отличие в цвете
        if (h<=(huesel+15) && h>=(huesel-15) &&
            s<=(satsel+15) && s>=(satsel-15) &&
            br<=(brsel+150) && br>=(brsel-150))
        {    
          //добавляем координату к общей сумме
          sumX+=i;
          sumY+=j;
          ii++;   
          //делаем найденный пиксель красным
          color cch = color(255,0,0);
          set(i,j,cch); //set(i,j-1,cch);set(i-1,j-1,cch);
        }

    }
  }
  
  //вычисляем центр фигуры из найденных пикселей
  float cX = sumX/ii;
  float cY = sumY/ii;
  
  //рисуем перекрестие
  strokeWeight(5);
  stroke(255,0,0);
  point(cX,cY);
    strokeWeight(1);
    line(cX,0,cX,height);
    line(0,cY,width,cY);
  
  //перевод координат в мм
  float cXmm = cX*167/320;
  float cYmm = cY*125/240;
  fill(230,0,0);
  text("X"+" "+cXmm,width-50,20);
  text("Y"+" "+cYmm,width-50,40);
  
  //Запись кадров
 //saveFrame("frames2/####.tiff");  
}

//обработчик указания мыши - захват цвета указанного пикселя
void mouseClicked(){
  color col = get(mouseX,mouseY);
  huesel = hue(col);
  satsel = saturation(col);
  brsel  = brightness(col);
}

 

Сама обработка захваченной картинки (функция draw() ) заключается в обходе всех пикселей в двойном цикле for. Внешний цикл по столбцам по координате Х экрана – перебираем все по счетчику i от нулевого до ширины экрана width.

Внутренний цикл по координате Y перебирает все пиксели данного столбца (выбранного во внешнем цикле) двигаясь по счетчику j от нулевой строки до height.

Получить цвет пикселя можно по его координатам на экране функцией get(i,j)

Сравнивая цвет текущего пикселя с заданным цветом, в блоке if решаем, принадлежит этот пиксель к выбранной мишени или нет. 

 

Функция mouseclicked() нужна для указания требуемого цвета.

Используемая кодировка цвета – HSB. В этой кодировке собственно оттенок цвета задан первым значением, по которому удобно сравнивать пиксели.

 

Центр фигуры определяется как отношение суммы координат точек к их числу.

 

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

 

 

December 16, 2018 finereader No comments exist

Робот манипулятор. Алгоритм управления

 

  • robmodel2
  • robmodel1

Создадим систему управления роботом и разработаем алгоритм управления его движением.

 

Задача системы управления (СУ) – определять ошибку между требуемым и текущим положениями схвата робота, рассчитывать перемещения отдельных звеньев и выдавать управляющий сигнал на серво-двигатели.

 

Наша СУ будет состоять из сервоприводов (SG-90), платы Arduino и ПК с программой, получающей координаты цели и рассчитывающей требуемые углы поворота серв.

Общий алгоритм управления Роботом такой:

  • Определить требуемое положение схвата: схват должен придти в точку цели. Цель можно указать мышкой, написав программу на компьютере (например в Processing) или обработать изображение с камеры, висящей над рабочей зоной робота, выделив на нем объект нужного цвета или формы.

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

  • Передача рассчитанных требуемых углов в Arduino. А дальше есть библиотека Servo и команда Servo::write(угол). Но попытка просто использовать эту функцию может привести к тому, что в случае требования повернуться на большой угол (например 180 град), серво-двигатель попытается мгновенно придти в указанное положение. Робот имеет некоторую массу и обладает инерцией, а это значит, что он будет сопротивляться изменению своей скорости. Силы инерции могут сорвать зубья шестеренок сервы. Необходимо попытаться сгладить переход между положениями, растянув его во времени.

Разобьем весь переход на несколько временных шагов и на каждом будем двигаться на долю, пропорциональную (составляющую часть) ошибке: Kp*error. Это еще называется пропорциональный регулятор (П-регулятор). 

 

Итак, микроконтроллер, получив значение требуемого угла поворота, рассчитает ошибку положения (текущее положение доступно из Servo::read()) и за некоторое количество тактов плавно переместит робота. От коэффициента пропорциональности зависит плавность.

 

 

Сейчас о том, как рассчитать требуемые положения звеньев робота.

Тут понадобятся базовые знания геометрии о прямоугольном треугольнике, соотношении его сторон в теореме Пифагора, откуда берутся синусы и косинусы. 

Сведения из геометрии

  • sin1
  • sin2
  • sin3
  • sin4
  • sin5
  • sin6
  • sin7

Программа на Processing с наглядной демонстрацией того, что sin(А) – это просто средство расчета противолежащего углу А катета.

 

 

Робот имеет 3 степени свободы (3 цилиндрических шарнира – 3 оси вращения), что позволяет перемещаться схвату по трем координатам xyz, но мы ограничимся плоскостью xy. 

На виде в плане (сверху то есть) мы видим схему робота и точку положения мишени с координатами xy, которые нам известны. Зная координаты, рассчитываем общий вылет робота – С (гипотенуза = сумме квадратов катетов). Угол поворота основания рассчитывается как дуга, соответствующая sin (y/c).

 

Робот_расчет1

Робот_расчет2

 

На профильном виде А-А, соединив точки центров серв и схвата, получим треугольник со сторонами L1 L2 R. Длина стороны R рассчитывается из прямоугольного треугольника СhR (где h-высота основания робота).

Но как быть с треугольником L1 L2 R- все стороны мы знаем, а углы нет. Оказывается, в любом треугольнике, имея длины его сторон можно найти его углы по теореме косинусов (или сторону, лежащую напротив известного угла, образованного двумя известными сторонами).

 

 

 

Теперь напишем модель робота в среде Processing и протестируем алгоритм.

Программа, как и Arduino, должна иметь две обязательные функции – setup() и draw(бесконечный цикл).

 

Создаем глобальные переменные для хранения размеров звеньев робота и текущих углов поворота этих звеньев, а также окно 800х600:

 

/* Переменные с размерами робота*/
float c = 0.0;  //вылет робота
float h = 80;   //высота основания
float L1 = h*3; //плечо
float L2 = h*4; //предплечье

/* Переменные с углами робота*/
  float alfa;
  float Beta,Beta2;
  float gamma;
  float tau,tau2;

void setup(){
  size(800,600,P3D);
}

 

В функции draw() на каждом такте перерисовки экрана :

 – отображаем мишень по координатам мыши

 – переносим систему координат в удобное место для отрисовки первого звена (основания)

 – рассчитываем положения звеньев робота

 – отрисовываем звенья основания, плеча и предплечья (с поочередным переносом систем координат)

 

void draw(){
  
  //Очищаем окно
  //background(#EAD5D5);

  /*Рисуем цель-мишень по координатам мыши*/
  drawTarget();
  
  //Перенос системы координат
  //и поворот
  //Y /\
  //X >>>
  translate(width/4,height/2+height/4);
  rotateX(radians(180));
  
  /* Рассчитываем положение робота - углы*/
  computeRobotpos();
  
  //Рисуем Основание Робота
  drawBase();
  
  //Рисуем Плечо Робота
  drawArm();

  //Рисуем Предплечье Робота
  drawForeArm();
}

 

 

Функция расчета положений звеньев – computeRobotpos() – смотри картинку выше

 

void computeRobotpos(){
  //Вылет Робота
  float c = (mouseX-width/4);
  float R = sqrt(h*h + c*c);
   alfa = asin(h/R);
   Beta = acos( (L1*L1 + L2*L2 - R*R) / (2*L1*L2));
   gamma = acos( (L1*L1 + R*R - L2*L2) / (2*L1*R));
   tau = gamma - alfa;
}

 

 

Функции отрисовки звеньев нехитрым образом переносят СК в точку начала следующего звена, поворачивают её на рассчитанный угол и командой line() чертят линию вдоль оси Х, по длине совпадающую с длиной данного звена:

 

void drawBase(){
  //Точка центра
  strokeWeight(3);
  stroke(255,255,0);
  point(0,0);
  
    strokeWeight(3);
    stroke(255,255,0);
  line(0,0,0,h);
    strokeWeight(15);
    point(0,h);
  drawlocalCS();
}

void drawArm(){
  //переносим систему координат
  //в точку начала звена
  translate(0,h);
  rotateZ((tau));
  
    strokeWeight(3);
    stroke(255,255,0);
  line(0,0,L1,0);
    strokeWeight(15);
    point(L1,0);
  drawlocalCS();
}

void drawForeArm(){
  //переносим систему координат
  //в точку начала звена
  translate(L1,0);
  rotateZ(-(PI-Beta));
  
    strokeWeight(3);
    stroke(255,255,0);
  line(0,0,L2,0);
    strokeWeight(15);
    point(L2,0);
  drawlocalCS();
}