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. Или в комментариях. Ниже приведено видео демонстрирующие работу программы. Спасибо за уделенное время. До встречи. Видео работы программы.
|
Категория: ЖЕЛЕЗО/ПРОГРАММИРОВАНИЕ. | Просмотров: 621 | | |
Всего комментариев: 0 | |