Главная » 2017 » Октябрь » 24 » Отладка по USB.
08:56
Отладка по USB.

Приветствую Вас. Сегодня речь пойдет об отладки электронного устройства по последовательному соединению. Мы не будем рассматривать конкретное устройство. Наверняка, если только вы не начали интересоваться Ардуино сегодня, у вас есть какие нибудь проекты которые подойдут для экспериментов. Мы будем проводить свои с сервоприводом. Но вам не составит труда адаптировать код под свои нужды. Мы намеренно используем простую структуру кода, операторы и функции знакомые новичку. Предполагается что вы имеете представление о чем идет речь.

Бывает необходимо получать данные телеметрии. Либо проводить отладку какого либо блока, органа, механизма не имея точных данных его настройки. С этим часто сталкиваются разработчики новых устройств. И здесь мы не рассматриваем какие-то несуществующие ранее механизмы. Речь идет об относительно простых вещах, например: свет, который включается по приближению к зеркалу; шторы отъезжающие по интенсивности света за окном; или ограничения поворота манипулятора робота. Все эти вещи требуют настройки - отладки. И дальномер, и фоторезистор, и сервопривод. Часто на практике все эти компоненты, особенно недорогие, ведут себя не так-как в теории. 

Подбирать значения каждый раз перепрошивая микроконтроллер неудобно. Тем более количество перепрошиваний контроллера хоть и велико, но не бесконечно. Здесь нам на помощь придет отладка по USB, а точнее по последовательному (или сериал/serial) соединению. Конечно этот способ не самый "крутой" и главным его минусом является физическая привязка к ПК. Которая накладывает серьезные ограничения на отладку движущихся и летающих устройств. Тем не менее, плюсом такой отладки как раз и является отсутствие дополнительных компонентов и модулей связи. Которым может понадобиться дополнительное питание, программное обеспечение и отладка. Как на стороне устройства, так и на стороне ПК.

Конечно же нам следует писать скетч для Ардуино с учетом его отладки. И несмотря на то, что это увеличивает объём кода и усложняет его. В последствии это ускорит и упростит нам задачу. Также нам понадобится софт для ПК. В данном случае, как и в некоторых других, мы используем язык программирования Processing. Его сходный с Arduino IDE синтаксис и бесплатность, делают его отличным решением для наших задач.

В большинстве случаев, настройка или как принято называть - отладка, сводится к подбору подходящих значений переменных. Этим мы и будем заниматься. Возможно вы пользовались монитором последовательного порта в Arduino IDE. И отправляли какие-либо данные в свою Ардуино. Мы будем делать тоже самое, только используя "дружественный интерфейс". Потому что отправлять наборы чисел используя монитор порта неинтересно.      

Если вы еще не скачали среду программирования Processing, сделайте это - СКАЧАТЬ (ссылка на оф. сайт). 

Как уже упоминалось, для своих экспериментов мы используем сервомотор.

Наш серво вращается на 180 градусов. Параметры которые мы собираемся настраивать:

1. Мы назовем это -"центр". Это положение вала двигателя относительно его максимума и минимума вращения в градусах. В идеале это 90 градусов.

2. Это угол отклонения от "центра". Наш серво должен поворачиваться поочередно по часовой и против часовой стрелки, выполняя какую-либо работу.

3. Это время за которое сервомотор будет выходить на заданную позицию. Скорость вращения вала с позиции 1 до позиции 2. 

Ниже приведена демонстрационная анимация цикла работы сервомотора.



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

- ввод данных и передачу их в Ардуино.

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

Вот незамысловатый интерфейс нашего приложения. 

Но начнем с программирования Ардуино. Ниже приведен скетч.


 

// Created by Mikhail Phomenko
// Special for Prototype3d.xyz

#include <Servo.h> // подкл.библ.
Servo MyServo; // создаем обект MyServo
// Установим значения поумолчанию
int center = 90; //Центр
int angle = 10;// Угол
int wait = 5;//Задержка

int GETcenter;
int GETangle;
int GETwait;

void setup() {
  Serial.begin(9600); // Создание последовательного соединения
  MyServo.attach(9); // Подклучаем серво к пину 9
}

void loop() {
  for (int i = 0; i < angle; i++) { // Поворот влево
    MyServo.write(center - i);
    delay(wait);
  }
  for (int i = 0; i < angle; i++) { // Возврат в центр
    MyServo.write((center - angle) + i);
    delay(wait);
  }
  for (int i = 0; i < angle; i++) { // Поворот вправо
    MyServo.write(center + i);
    delay(wait);
  }
  for (int i = 0; i < angle; i++) { // Возврат в центр
    MyServo.write((center + angle) - i);
    delay(wait);
  }
  Serial.print(String(center) + "," + String(angle) + "," + String(wait) + "," + '\n');

  while (Serial.available() > 0) {
    GETcenter = Serial.parseInt();
    GETangle = Serial.parseInt();
    GETwait = Serial.parseInt();
    if (Serial.read() == '\n') {
      GetVar();
    }
  }
}
void GetVar() {
  center = GETcenter;
  angle = GETangle;
  wait = GETwait;
}


Рассмотрим код по частям.

Вначале мы подключаем библиотеку, создаем объект MyServo, создаем глобальные целочисленные переменные.

#include <Servo.h>  

Servo MyServo;

int center = 90;

int angle = 10;

int wait = 5;

int GETcenter;

int GETangle;

int GETwait;

//

В функции setup установим последовательное соединение и управляющий пин сервомотора.

void setup() {

Serial.begin(9600);

MyServo.attach(9);

}

//

В функции loop расположены четыре цикла for. Они последовательно вращают серву.

void loop() {

for (int i = 0; i < angle; i++) { // Поворот влево

MyServo.write(center - i);

delay(wait);

}

for (int i = 0; i < angle; i++) { // Возврат в центр

MyServo.write((center - angle) + i);

delay(wait);

}

for (int i = 0; i < angle; i++) { // Поворот вправо

MyServo.write(center + i);

delay(wait);

}

for (int i = 0; i < angle; i++) { // Возврат в центр

MyServo.write((center + angle) - i);

delay(wait);

}

//

Далее мы отправляем значения переменных (фактические значения с которыми работает сервомотор) на ПК. А в функции while принимаем значения с ПК (отладочные значения). ParseInt можно перевести как - разобрать целое. Этот оператор ищет в принятой, по последовательному порту, строке целые числа разделенные запятой, точкой и прочим. При получении знака новая строка ('\n') вызываем функцию GetVar()  

Serial.print(String(center) + "," + String(angle) + "," + String(wait) + "," + '\n');

while (Serial.available() > 0) {

GETcenter = Serial.parseInt();

GETangle = Serial.parseInt();

GETwait = Serial.parseInt();  

if (Serial.read() == '\n') {

GetVar();

}

}

//

GetVar() - функция в которой мы присваиваем полученные значения переменным, которые управляют сервомотором в главном цикле программы (цикл loop).

void GetVar() {

center = GETcenter;

angle = GETangle;

wait = GETwait;

}


Это все что нам нужно от Ардуино. Перейдем к коду на Processing. И как всегда надеемся что вы скачали и смогли запустить эту среду разработки. Несмотря на кажущуюся объемность, код простой. А его объем обусловлен неоптимизированным написанием. Что способствует лучшему пониманию его работы.

Листинг программы на Processing.


 

import processing.serial.*; // Подкл. библиотеки последовательного порта

Serial myPort; // Создание объекта myPort
String model = "Отладка по USB."; // Строковая переменная 
String dataServo = "12,34,56"; // Строковая переменная 
String [] data = {"0", "0", "0"}; // Массив строковых переменных
int center = 90; // Переменная центр
int angle = 10; // Переменная угол
int wait = 5; // Переменная задержка

// Координаты лого
int xproto = 5; // Переменная координата X
int yproto = 175; // Переменная координата Y

void setup() {
  size (300, 200); // Размер окна
  myPort = new Serial(this, "COM3", 9600); // Создание подключения 
  myPort.bufferUntil('\n'); // Устанавливаем значение срабатывания функции serialEvent
}

void draw() {
  background(0); // Цвет фона 
  fill(255); // Цвет заливки
  textSize(8); // Размер шрифта
  rect (0, 30, 300, 140); // Прямоугольник

  // logo Prototype3D
  noStroke();
  fill (250, 50, 50);
  rect (xproto, yproto, 5, 15);
  text ("P", xproto, yproto+23);
  fill (50, 250, 50);
  rect (xproto+7, yproto+5, 5, 10);
  text ("3", xproto+7, yproto+23);
  fill (50, 50, 250);
  rect (xproto+14, yproto+10, 5, 5);
  text ("D", xproto+14, yproto+23);

  stroke(100); // Цвет обводки
  strokeWeight(2); // Толщина обводки
  text (model, 100, 20); // Текст
  fill(0); // Цвет заливки
  noFill(); // Отключаем заливку примитивов
  // Центр
  rect (50, 50, 20, 20, 5, 0, 5, 0); // Прямоугольник
  text("ЦЕНТР (в градусах)", 80, 65); // Текст
  line (80, 70, 180, 70); // Линия
  // Угол
  rect (50, 80, 20, 20, 5, 0, 5, 0); // Прямоугольник
  text("УГОЛ (в градусах)", 80, 95); // Текст
  line (80, 100, 180, 100); // Линия
  // Задержка
  rect (50, 110, 20, 20, 5, 0, 5, 0); // Прямоугольник
  text ("ЗАДЕРЖКА (в миллисек.)", 80, 125); // Текст
  line (80, 130, 180, 130); // Линия

  // Вывод переменных
  text (center, 53, 63); 
  text (angle, 53, 93);
  text (wait, 53, 123);

  // Вывод данных принятых от Ардуино
  textSize(20); // Размер шрифта

  // Заполняем массив data данными полученными с Ардуино.
  // Оператор split разделяет строку по указанному в кавычках символу.
  String [] data = split (dataServo, ",");

  // Проверка и вывод данных.
  // Центр
  if (int (data[0]) == center) {
    fill(0);
  } else {
    fill(200, 50, 50);
  }
  text (data[0], 190, 70);

  // Угол
  if (int (data[1]) == angle) {
    fill(0);
  } else {
    fill(200, 50, 50);
  }
  text (data[1], 190, 100);

  // Задержка
  if (int (data[2]) == wait) {
    fill(0);
  } else {
    fill(200, 50, 50);
  }
  text (data[2], 190, 130);
}

// Функция событий мыши (колесико).
// Изменение и отправка параметров
void mouseWheel(MouseEvent event) { 
  int e = event.getCount();

  if (mouseX > 50 & mouseX < 70) {
    if (mouseY > 50 & mouseY < 70) {
      if (e == 1 & center < 120) {
        center ++;
        Sent(); // Вызов функции отправки данных.
      }
      if (e == -1 & center > 60) {
        center --;
        Sent(); // Вызов функции отправки данных.
      }
    }
    if (mouseY > 80 & mouseY < 100) {
      if (e == 1 & angle < 40) {
        angle ++;
        Sent(); // Вызов функции отправки данных.
      }
      if (e == -1 & angle > 0) {
        angle --;
        Sent(); // Вызов функции отправки данных.
      }
    }
    if (mouseY > 110 & mouseY < 130) {
      if (e == 1 & wait < 20) {
        wait += 1;
        Sent(); // Вызов функции отправки данных.
      }
      if (e == -1 & wait > 0) {
        wait --;
        Sent(); // Вызов функции отправки данных.
      }
    }
  }
}

void Sent() { // Функция отправки данных в Ардуино
  myPort.write (center + "," + angle + "," + wait+'\n');
}

void serialEvent (Serial myPort) { // Функция приема данных с Ардуино
  dataServo = (myPort.readStringUntil('\n'));
}


Рассмотрим основные моменты кода.

//

В начале как всегда подключаем библиотеки, создаем и назначаем значения переменным. Здесь нам стоит обратить внимание на массив строковых данных String [] data = {"0", "0", "0"};. В ячейки которого занесены нули. В дальнейшем массив будет содержать данные центра, угла и задержки, с которыми фактически работает Ардуино. При старте программы они равняются нулю. Так же переменная String dataServo = "12,34,56";, эта строка будет принимать данные от Ардуино. 12, 34, 56 - это просто любые данные строкового типа. Мы их определили чтобы при старте наша программа не писала ошибку что dataServo = null. 

import processing.serial.*; // Подкл. библиотеки последовательного порта

Serial myPort; // Создание объекта myPort

String model = "Отладка по USB."; // Строковая переменная

String dataServo = "12,34,56"; // Строковая переменная

String [] data = {"0", "0", "0"}; // Массив строковых переменных

int center = 90; // Переменная центр

int angle = 10; // Переменная угол

int wait = 5; // Переменная задержка

//

Отправленные данные в Processing из Ардуино оператором Serial.print(String(center) + "," + String(angle) + "," + String(wait) + "," + '\n');. Мы принимаем как одну цельную строку. В которой данные нам представлены цифрами (не числами), разделенные запятой. Для того чтобы мы могли работать с каждым значением по отдельности, мы воспользуемся функцией String [] data = split (dataServo, ",");. Эта функция разделит полученную строку по указанному в кавычках символу. И полученные значения поместит в ячейки массива data. С которыми мы и будем работать при проверке и выводи данных о фактических параметрах работы сервомотора. Мы не будем рассматривать каждую строчку кода, предполагая что с этими операторами и функциями вы знакомы.  

Вопросы задавайте в нашей группе VK. Или в комментариях.

Ниже приведено видео демонстрирующие работу программы.

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


Видео работы программы.


 

Категория: ЖЕЛЕЗО/ПРОГРАММИРОВАНИЕ. | Просмотров: 528 | Добавил: prototypestudio | Теги: com, Processing, Arduino, программирование ардуино, отладка, Serial, ардуино, USB, процессинг
Всего комментариев: 0
Добавить комментарий