Ардуино про мини и 17 сервоприводов
- Войдите на сайт для отправки комментариев
Чт, 11/02/2021 - 11:09
Собираю гуманоидного робота на 17 сервах. Для экономии использую про мини, hc-05. Как подправить библиотеку для корректной работы всех приводов? Тренировочно-проверочный скетч (реальный (часть строк закомментирована) и желаемый (исправлено число серв)) такой.
#include <Servo.h> // подключение библиотеки Servo #define kolvoSV 17//количество сервоприводов Servo servo[kolvoSV]; int i=0;//счётчик элементов массивов int n; String inputString;// строки данных void setup() { Serial.begin(57600); for(i=0;i<kolvoSV;i++){servo[i].attach(i+2);servo[i].write(90);delay(20);}//начальные установки углов 90 градусов (подкл. на выводы начиная со 2 по возр.) //если не трогать библиотеку... /*servo[10].attach(14);servo[10].write(90);delay(200); servo[10].attach(15);servo[10].write(90);delay(200); servo[10].attach(16);servo[10].write(90);delay(200); servo[10].attach(17);servo[10].write(90);delay(200); servo[10].attach(18);servo[10].write(90);delay(200);*/ } void loop() { CheckSerial(); } //////////////////////////////////////////////////////////////////////////////////////////////// //ФУНКЦИИ ПРИЁМА И ОБРАБОТКИ КОМАНД-ДАННЫХ void MakeCmd() { int y = inputString.length(); // присваиваем переменной у число символов в строке if (y < 1 || y > 5){inputString = "";return;} //если их меньше 1 или больше 5, выходим из функции String cmd = inputString; // передаём строку другой переменной inputString = "";//"обнуляем переменную" ////// if (cmd == "0") { //если получили ноль Serial.write(0x14); // ответить avrdude.exe Serial.write(0x10); // для синхронизации delay(10); pinMode(19,OUTPUT); //ЭТО ВЫЗОВЕТ аппаратный РЕСЕТ } //////// //////// if (cmd != "0"){ n=cmd.toInt();} // преобразуем строку в команды сервоприводам... for(i=0;i<kolvoSV;i++) { if(n>=(i+1)*1000&&n<(i+1)*1000+181){servo[i].attach(i+2);servo[i].write(n-(i+1)*1000);} } //если не трогать библиотеку... /* if(n>=13000&&n<13181){servo[10].attach(14);servo[10].write(n-13000);}//управление дополнительными сервоприводами (поворот качалок без удержания их под нагрузкой) if(n>=14000&&n<14181){servo[10].attach(15);servo[10].write(n-14000);} if(n>=15000&&n<15181){servo[10].attach(16);servo[10].write(n-15000);} if(n>=16000&&n<16181){servo[10].attach(17);servo[10].write(n-16000);} if(n>=17000&&n<17181){servo[10].attach(18);servo[10].write(n-17000);}*/ ////// ////// } /////////////////////////////////////////////////////////////////////////////////////////////////////// void CheckSerial() { ////////////////////////////////////////////////////////////////////////////// while (Serial.available())//считываем строку данных пока они поступают { char inChar = (char)Serial.read(); if (inChar == '\n'||inChar == ' ') //если окончание строки или запрос на загрузку { MakeCmd();//обрабатываем её данной функцией break; } else inputString += inChar;// иначе удлиняем строку на один символ } } /////////////////////////////////////////////////////////////////////////////////
Собираю гуманоидного робота на 17 сервах. Для экономии использую про мини,
простите, "для экономии" чего?
Экономии всего - простая доступная версия робота. Схематехника - про мини, 17 sg90 (mg90), блютуз модуль, два 18650, dc-dc до 5 В понижающий, выключатель, шасси - пластиковые детальки печатные, максимум одинаковых с заполнением 40, заливка скетчей по воздуху.
и в чем у вас проблема? Зачем править библиотеку?
17 sg90 (mg90)
два 18650, dc-dc до 5 В понижающий
Смешно. Не получится у тебя никакого робота. Для таких вещей нужен опыт ходьбы по граблям, а ты просто набрал кучу дешевого хлама, и думаешь что получится конфета.
17 sg90 (mg90)
два 18650, dc-dc до 5 В понижающий
Смешно. Не получится у тебя никакого робота. Для таких вещей нужен опыт ходьбы по граблям, а ты просто набрал кучу дешевого хлама, и думаешь что получится конфета.
Опыта хватает, это лишь продолжение после 2, 4,8,12 серв дешёвых на разных типах ходунов из пластика печатного. Вы знаете как поправить библиотеку?
и в чем у вас проблема? Зачем править библиотеку?
Дело в том, что не все качалки будут держать нагрузку, для рук это терпимо, для ног нет. Просто хочется знать знать предел элементарного использования простых вещей). Кстати щёлкающие и клинящие sg90 легко чинятся.
Вы знаете как поправить библиотеку?
Зачем ее править? Она что, ошибку выдает? - если да - выкладывайте сообщение об ошибке
))))
Она не выдаёт ошибку, она 13,14,15,16,17 серву не вращает, если просто так взять и задать в скетче вместо 12 - 17
Она не выдаёт ошибку, она 13,14,15,16,17 серву не вращает, если просто так взять и задать в скетче вместо 12 - 17
Вы ошибочно считаете, что число поддерживаемых моторов 12 поставлено в библиотеке "от балды" разработчиками, которые пожмотились написать 17. Это не так. Возможности микроконтроллера не резиновые.
Берите мегу, там поддерживаются 48 моторов.
Ящик Пандоры открывался легко )
В файле Servo.h
строку
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
меняем на
#define SERVOS_PER_TIMER 17 // the maximum number of servos controlled by one timer
По Фрейду
По Фрейду
"сколько будет дважды два - семь учитель...семь, восемь, где-то так, но не сорок же..."
разогнал ведь сцуко библиотеку... сначала железо модно было гнать - оверклоцкеры, теперь софт гонят - овербиблеры
интересно, насколько оно у него работать будет? - зависит от углов размаха ногами, видимо :)
Посмотрел исходник - физического ограничения на число серв в коде и правда нет, главное чтобы оно успевало все сервы открутить за полный цикл таймера.
Ипользуется 16-битный таймер с делителем 8, при 16 МГЦ это 2 тика за микросекунду. Диапазон сигналов серв - до 2400 мкс
Итого получаем 0xFFFF / (2400*2) = 13.6 серв на таймер
То есть гарантировано успеет обработать 13 серв, дальше как повезет :)
Нашему ТС, вместо того чтоб тупо менять число серв, стоило бы переставить делитель на таймере, чтобы тот тикал помедленнее. Немного упадет точность позиционирования, зато на одну ардуину, теоретически, можно будет навешать хоть сотню серво моторов :)
Хотя не.. пинов не хватит :).
ото ж. Это тоже спокойно гонится. Ищешь свободное место на плате, сверлишь дырочки... В этом плане уна лучше гонится по сравнению с промини.
ЗЫ. Мы в свое время мониторы CRT с 15 до 17 разгоняли. Особые экземпляры до 19 гнались. Но это канало только с выпуклым экраном. Плоские к разгону были не чувствительны.
интересно, насколько оно у него работать будет? - зависит от углов размаха ногами, видимо :)
Посмотрел исходник - физического ограничения на число серв в коде и правда нет, главное чтобы оно успевало все сервы открутить за полный цикл таймера.
Ипользуется 16-битный таймер с делителем 8, при 16 МГЦ это 2 тика за микросекунду. Диапазон сигналов серв - до 2400 мкс
Итого получаем 0xFFFF / (2400*2) = 13.6 серв на таймер
То есть гарантировано успеет обработать 13 серв, дальше как повезет :)
Нашему ТС, вместо того чтоб тупо менять число серв, стоило бы переставить делитель на таймере, чтобы тот тикал помедленнее. Немного упадет точность позиционирования, зато на одну ардуину, теоретически, можно будет навешать хоть сотню серво моторов :)
Хотя не.. пинов не хватит :).
Проверял таким аналогичным скетчем. Три сервы перетыкивал на уно по выходам разным, вроде работает справно. Из вашей подсказки понял, что библиотека штатно рассчитана на 13 приводов. И для "надёжности более глубокой" надо изменить делитель таймера на 64?, влезая в дикие дебри регистров.
Из вашей подсказки понял, что библиотека штатно рассчитана на 13 приводов. И для "надёжности более глубокой" надо изменить делитель таймера на 64?, влезая в дикие дебри регистров.
нет, "штатно" она рассчитана на 12. Но на 13-ти гарантировано будет работать. Все что выше - на ваш страх и риск.
Но если рассуждать оптимистично :). то скорее всего и 15, и 17 серв будут работать без всяких правок таймера - просто потому, что вы крайне редко используете все 17 серв на полную катушку одновременно.
Можно посмотреть в сторону LGT8F328P - ничего не меняя, имеем 32 МГц на платах типа pro mini, nano, да и дешевле.
Можно посмотреть в сторону LGT8F328P - ничего не меняя, имеем 32 МГц на платах типа pro mini, nano, да и дешевле.
Ну тут надо заказать, дождаться, поставить расширение, научиться пользоваться новой платой...
а тут убиться, ища где поправить файл :)
Просто следующий аппаратный зигзаг - включить две про мини на один блютуз, поочерёдно заливать по воздуху скетчи уже для 34 серв :)
Для правки нашёл такую строку для первого таймера (тот, не тот микроконтроллер?)
TCCR1B = _BV(CS11); // set prescaler of 8
и ещё две подозрительные на исправление :
ну я не знаю, 2400мксек это стандарт на максимальную длительность сигнала PWM видимо
Но если рассуждать оптимистично :). то скорее всего и 15, и 17 серв будут работать без всяких правок таймера - просто потому, что вы крайне редко используете все 17 серв на полную катушку одновременно.
Заинтересовала эта тема. До этого с сервами не работал, так что могу ошибаться. Но (на первый взляд) переполнение таймера не должно прервать или сбить обслуживание "старших" серв. Период только может превысить 20 мс.
Дополнение. Если не вносить в код изменения, то при переполнении таймера, период возрастет сразу в два раза до 40 мс. Если отслеживать факт переполнения, то можно уменьшить период до реально необходимого значения. Но пока не проверял, не будет ли сбоев, если в результате вычислений OCR1A станет = 0, но вроде не должно.
Интересная гипотеза. Пока из особенностей 17 вместо 12 заметил , что при подходе качалок к 180 градусам плавность хода слегка заменяется скачками, появляется шелест. Поменял в библиотеке период повтора упр. импульсов на 10, 15,25 мс. Ничего не изменилось, но при наименьшем значении шелест стал существенно тише.
Надо бы попробовать всёж поставить таймер1 на делитель 64, но чего то страшно:)
Надо бы попробовать всёж поставить таймер1 на делитель 64, но чего то страшно:)
а чего боятся... это ж не обрезание. если не заработает - вернете обратно :)
Так с таймером и не получилось, исправлял- не работала библиотека. Но в целом 17 серв работают как и 12 :)
Класс
Поменял в библиотеке период повтора упр. импульсов на 10, 15,25 мс. Ничего не изменилось, но при наименьшем значении шелест стал существенно тише.
При периоде повтора 20 мс, после обслуживания последнего серво проверяется - отсчитал ли таймер 20 мс. Если больше 20 мс, то таймер сбрасывается и начинается новый период. Если меньше 20 мс то ждет пока досчитает до 20 мс и тогда сбрасывает и начинаем новый период. Но если серв много, и произойдет переполнение таймера (32 мс), то после обслуживания последнего серво информации о переполнении не учитывается и ждет очередные 20 мс. Итого период становится 32+20=52 мс. Если добавить проверку флага переполнения таймера после обслуживания последнего серво, то при переполнении можно начинать новый период сразу (не забыв сбросить флаг). Когда вы ставили период повтора 10 мс, то вы уменьшали период в случае переполнения с 32+20=52 до 32+10=42.
Поменял в библиотеке период повтора упр. импульсов на 10, 15,25 мс. Ничего не изменилось, но при наименьшем значении шелест стал существенно тише.
Если добавить проверку флага переполнения таймера после обслуживания последнего серво, то при переполнении можно начинать новый период сразу (не забыв сбросить флаг).
Найти бы это ещё :)
Пока уловил, что период повтора надо снизить до 2-0 мс - хотя это неграмотное решение.
Не все сервы хорошо относятся к снижению частоты ШИМ.
Пока уловил, что период повтора надо снизить до 2-0 мс - хотя это неграмотное решение.
Если использовать этот вариант ТОЛЬКО для большого числа серв, то проблем быть не должно (по моему). Есть сомнения в моменте подключения, т.к. если как у вас в коде стоят задержки после подключения каждой сервы delay(200); то некоторое время, до подключения всех серв, они могут работать с сильно повышенной частотой, что может быть вредно.
Но если с такой модификацией запустить для малого количества серв, то может быть плохо (вредно для серв).
Вариант с проверкой переполнения универсальный, но надо править код. Повторюсь - для 17 серв ваш вариант выглядит вроде нормальным. Только снижать не до 0. Какой допустимый минимум не считал, но меньше (например) #define REFRESH_INTERVAL 200 выигрыш пренебрежимо мал.
Для вашего конкретного случая можно попробовать обойтись малой модификацией
В 18 строке добавить проверку, что количество серв меньше 17. Тогда если их меньше 17, то (как и было) будет вставлено ожидание, а если нет, то сразу else с подготовкой к новому периоду.
Попробую добавить условие и посмотреть в макете на уно с парой серв.
При периоде повтора 20 мс, после обслуживания последнего серво проверяется - отсчитал ли таймер 20 мс.
Это понятно.
Если больше 20 мс, то таймер сбрасывается и начинается новый период.
Соответственно "опоздав" на время = (время исполнения вектора isr) - 20мс (или 32), верно?
Если меньше 20 мс то ждет пока досчитает до 20 мс и тогда сбрасывает и начинаем новый период.
В таком случае код "успевает" за тиками таймера и тики происходят без задержек и в строго отведённые временные рамки, верно?
Но если серв много, и произойдет переполнение таймера (32 мс), то после обслуживания последнего серво информации о переполнении не учитывается и ждет очередные 20 мс.
В таком случае выполнение вектора isr от таймера будет совершенно случайным и никак не привязанным ко времени тиков, верно?
========
В таком случае есть ли какой-нибудь метод определения, что таймер (isr) "успеет" посчитать и не "наехать" на другие события, например от других таймеров.
Например, имеем некую программу, в которой есть всего 3 вектора и они выполняются за определённый % времени. В таком случае имеем 3 разные модели поведения:
1 - (1 isr = 10%), (2 isr = 20%), (3 main < 70%); 10 + 20 + <70 = <100% === всё прекрасно работает.
2 - (1 isr = 10+-5%), (2 isr = 20+_5%), (3 main < 70+-10%); ~10+-5 + ~20+-5 + ~70+-10 = ~100+-20% === имеем "плавающий" непостоянный глюк.
3 - (1 isr > 10%), (2 isr > 20%), (3 main > 70%); >10 + >20 + >70 = >100% === нихрена ничего не работает так как нужно.
Например, вот так.
Из вашей подсказки понял, что библиотека штатно рассчитана на 13 приводов. И для "надёжности более глубокой" надо изменить делитель таймера на 64?, влезая в дикие дебри регистров.
нет, "штатно" она рассчитана на 12. Но на 13-ти гарантировано будет работать. Все что выше - на ваш страх и риск.
Но если рассуждать оптимистично :). то скорее всего и 15, и 17 серв будут работать без всяких правок таймера - просто потому, что вы крайне редко используете все 17 серв на полную катушку одновременно.
правильно (2.4мсек) х (на количество серв)?
В таком случае есть ли какой-нибудь метод определения, что таймер (isr) "успеет" посчитать и не "наехать" на другие события, например от других таймеров.
Например, имеем некую программу, в которой есть всего 3 вектора и они выполняются за определённый % времени. В таком случае имеем 3 разные модели поведения:
1 - (1 isr = 10%), (2 isr = 20%), (3 main < 70%); 10 + 20 + <70 = <100% === всё прекрасно работает.
2 - (1 isr = 10+-5%), (2 isr = 20+_5%), (3 main < 70+-10%); ~10+-5 + ~20+-5 + ~70+-10 = ~100+-20% === имеем "плавающий" непостоянный глюк.
3 - (1 isr > 10%), (2 isr > 20%), (3 main > 70%); >10 + >20 + >70 = >100% === нихрена ничего не работает так как нужно.
Например, вот так.
Я не понял, что вы имеете в виду. Здесь используется обработчик по совпадению OCR1A, он приведен в #31.
Время выполнения обработчика примерно одинаково для любых условий (внутри обработчика ничего не ждут).
Да, с подсказкой вы оказались правы качалки серв в окрестностях 180 градусов практически перестали ступенчато двигаться.
тест скетч: