Comments 34
>>Видео, к сожалению, выложить не могу.
а схему?
а схему?
0
Это случайно не для России в миниатюре?
+1
Макет шикарен!
+3
Интересно зачем для атмеги такой суровый предохранитель?
+1
кучу if (takt == ..) можно заменить на один switch, читается лучше
+2
Да, действительно. Это неплохая мысль. Я просто скорее электронщик, чем программист.
+1
НА куче if получается несколько компактней. По крайней мере на AVR. Впрочем, тут смотреть надо. Может компилятор догадается развернуть кейс через индексный переход. Не всегда, но у него бывают такие озарения. Особенно у IAR.
+1
Если хочется поменьше условных переходов, то можно еще как-нибудь вот так можно написать.
unsigned int servo = takt / 2; // or takt >> 1
unsigned char angle = angles[servo];
unsigned char mask = 1 << servo;
if (takt & 1) {
PORTC &= ~mask;
OCR1A = cycle - angle;
} else {
PORTC |= mask;
OCR1A = angle;
}
takt = (takt + 1) & 7;
+2
максимальная скважность получается 25%?
0
>Примечательно, что оба аналоговых привода могли работать нормально только пару минут, а потом начинать произвольно дергаться, зажиматься в крайних положениях и т.д.
Вот это в высшей мере странно. Т.к. электроники внутри там почти нет. Тупейшая разностная схема которая зависит ТОЛЬКО от импульсов. А импульсы часом никуда не уплыли?
Бегло глянул на алгоритм — импульсы идут друг за другом, ширина периода каждого зависит от ширины соседей получается?
Вот это в высшей мере странно. Т.к. электроники внутри там почти нет. Тупейшая разностная схема которая зависит ТОЛЬКО от импульсов. А импульсы часом никуда не уплыли?
Бегло глянул на алгоритм — импульсы идут друг за другом, ширина периода каждого зависит от ширины соседей получается?
+1
Сервоприводы специально ездил проверял в магазин — с сервотестером любые работают отлично, но с моей электроникой аналоговые дружить отказываются. Я не смог найти этому никого разумного объяснения.
Частота фиксированная и определяется переменной cycle (хотя ее надо было прописать как константу). У меня период следования был 18000мкс и четыре привода. Я записал в cycle 4500мкс — это время которое отводится на управление одним приводом, то есть передние фронты импульсов задержаны друг относительно друга именно на это время. Когда прерывание вызывается в первый раз — в OCR1A записывается длительность импульса управления приводом. При втором срабатывании, когда импульс заканчивается, в OCR1A записывается (cycle-angle1), время которое осталось до перехода к следующему приводу. В итоге частота следования импульсов не зависит от длительности управляющих импульсов.
Частота фиксированная и определяется переменной cycle (хотя ее надо было прописать как константу). У меня период следования был 18000мкс и четыре привода. Я записал в cycle 4500мкс — это время которое отводится на управление одним приводом, то есть передние фронты импульсов задержаны друг относительно друга именно на это время. Когда прерывание вызывается в первый раз — в OCR1A записывается длительность импульса управления приводом. При втором срабатывании, когда импульс заканчивается, в OCR1A записывается (cycle-angle1), время которое осталось до перехода к следующему приводу. В итоге частота следования импульсов не зависит от длительности управляющих импульсов.
0
Чудес не бывает. Берите осциллограф и сравнивайте сигнал сервотестера и своей схемы. Где то там косяк. Скорей всего джиттер.
0
Ну, а из плюсов алгоритма. ОЧЕНЬ быстрая обработка прерывания. Это большой большой плюс.
Минус — плавающая частота импульсов. Не критично для положения, но критично для скорости вращения. Впрочем, тут не подразумевается разгон серв, так что влияние незначительное.
Минус — плавающая частота импульсов. Не критично для положения, но критично для скорости вращения. Впрочем, тут не подразумевается разгон серв, так что влияние незначительное.
+2
Почему не подходит аппаратный ШИМ на контроллерах?
+1
потому что их обычно 1-3, а для, скажем, гексапода нужно 12-16
+2
у 16 максимальная скважность будет 100/16
тут лучше использовать внешний PWM, например, tlc5940
тут лучше использовать внешний PWM, например, tlc5940
+1
Вставлю свои пять копеек.
За реализацию респект, уважение и поклон!
Но, критика ценнее и важнее похвалы. Тот кусок кода, который вы привели совершенно не переносим. Более того, если вы переставите сервопривод на другую ножку другого порта, вам придётся перепахивать всю программу.
Конкретно вот: PORTC |= 0b00000001; — это форменное безобразие и источник множества ошибок и проблем! Как это искоренить в коде я не представляю. Самое ужасное, что если вы решите перенести код на другой процессор, или о боже, другой архитектуры, то это будет весьма тривиальной задачей.
Я даже намедни писал пост по теме: dlinyj.livejournal.com/593356.html
Собтвенно говоря, у меня был случай, разные релюшки были разбросаны по разным портам и пинам, полностью хаотично. Самый лучший конечно способ был сделать структуру портов и масок, но у меня нехватило памяти контроллера и запала, и я сделал примерно так:
И далее обращался к ним вот так:
Самое ценное, что поменяв только дефайны, я могу перенести данный код даже на другой процессор, если там другой тип обращения к пинам порта, то поменять мкакросы. Мне не нужно для этого будет перепахивать весь код.
Надеюсь комментарий будет полезен.
За реализацию респект, уважение и поклон!
Но, критика ценнее и важнее похвалы. Тот кусок кода, который вы привели совершенно не переносим. Более того, если вы переставите сервопривод на другую ножку другого порта, вам придётся перепахивать всю программу.
Конкретно вот: PORTC |= 0b00000001; — это форменное безобразие и источник множества ошибок и проблем! Как это искоренить в коде я не представляю. Самое ужасное, что если вы решите перенести код на другой процессор, или о боже, другой архитектуры, то это будет весьма тривиальной задачей.
Я даже намедни писал пост по теме: dlinyj.livejournal.com/593356.html
Собтвенно говоря, у меня был случай, разные релюшки были разбросаны по разным портам и пинам, полностью хаотично. Самый лучший конечно способ был сделать структуру портов и масок, но у меня нехватило памяти контроллера и запала, и я сделал примерно так:
#define port_rele1 PORTA
#define ddr_rele1 DDRA
#define pin_rele1 PINA
#define port_rele2 PORTC
#define ddr_rele2 DDRC
#define pin_rele2 PINC
...
//pins define
//port_rele1
#define K1 5
#define K2 4
#define K3 3
#define K4 0
#define K5 1
#define K6 2
...
И далее обращался к ним вот так:
//инициализация
void hardware_init()
{
ddr_rele1 |=(1<<K1)|(1<<K2)|(1<<K3)|(1<<K4)|(1<<K5)|(1<<K6);
port_rele1 |=(1<<K1)|(1<<K2)|(1<<K3)|(1<<K4)|(1<<K5)|(1<<K6);
ddr_rele2 |=(1<<K7)|(1<<K8)|(1<<K9);
...
}
//для включения, выключения пользовался макросами
#define BIT_ON(port, bit) do {port |= (1<<bit);}while(0)
#define BIT_OFF(port, bit) do {port &=~(1<<bit);}while(0)
#define BIT_INVERCE(port, bit) do {port ^=(1<<bit);}while(0)
//пример управления:
BIT_OFF(port_rele1,K1);
Самое ценное, что поменяв только дефайны, я могу перенести данный код даже на другой процессор, если там другой тип обращения к пинам порта, то поменять мкакросы. Мне не нужно для этого будет перепахивать весь код.
Надеюсь комментарий будет полезен.
+3
Кодеры с работы тоже долго надо мной потешались. Просто у меня была очень конкретная разовая задача и я не уделил должного внимания улучшению читаемости кода. Кроме того здорово сроки поджимали — я перепробовал кучу вариантов управления и времени на финальную реализацию почти не осталось. Написал «чтобы работало». Следующим шагом будем думать над красотой кода. Спасибо за пример.
+2
Я так понимаю этот комментарий был адресован мне :).
Не нужно уделять внимание читаемости кода. Надо писать сразу читаемый код. Я начинаю написание программы с определения дефайнов, констант и конструкций. Ну так же флагов глобальных переменных, которые доввожу по мере необходимости.
Здесь нет места красоте. Поймите, что такой подход сокращает время разработки и уменьшает количество ошибок раз в десять!
Не нужно уделять внимание читаемости кода. Надо писать сразу читаемый код. Я начинаю написание программы с определения дефайнов, констант и конструкций. Ну так же флагов глобальных переменных, которые доввожу по мере необходимости.
Здесь нет места красоте. Поймите, что такой подход сокращает время разработки и уменьшает количество ошибок раз в десять!
+1
> Надо писать сразу читаемый код
Ну у вас тоже неидеальный код.
К примеру, стандарт де-факто — написание дефайнов только капсом.
Или я так и не понял что за сумрачная конструкция do/while(0), её используют часто для того чтобы можно break юзать вместо goto, но в данном случае совсем мне непонятно.
В дефайнах параметры не обернуты скобки:
BIT_ON(BASE_PORT + PORT_STATUS, 2 * i) очень удивит компилятор.
Ну и всякая мелочевка типа рандомной расставки пробелов.
Ну у вас тоже неидеальный код.
К примеру, стандарт де-факто — написание дефайнов только капсом.
Или я так и не понял что за сумрачная конструкция do/while(0), её используют часто для того чтобы можно break юзать вместо goto, но в данном случае совсем мне непонятно.
В дефайнах параметры не обернуты скобки:
BIT_ON(BASE_PORT + PORT_STATUS, 2 * i) очень удивит компилятор.
Ну и всякая мелочевка типа рандомной расставки пробелов.
+4
Ну и всякая мелочевка типа рандомной расставки пробелов.это не мой косяк, а косяк интрепретации хабром моего кода. У меня всё ок.
К примеру, стандарт де-факто — написание дефайнов только капсомвпервые слышу, быть может это конечно и оправданно.
Или я так и не понял что за сумрачная конструкция do/while(0), её используют часто для того чтобы можно break юзать вместо goto, но в данном случае совсем мне непонятно.Это макросы Аскольда Волкова, на сколько я понимаю использование ду вайл делается для переносимости кода. Не разбирался.
BIT_ON(BASE_PORT + PORT_STATUS, 2 * i) очень удивит компилятор.Силился представить, когда мне понадобится такая конструкция, но не смог… В особенности конструкция BASE_PORT + PORT_STATUS — не будет работать со сто процентной вероятностью. Но про скобки возможно замечание и стоящее.
+1
> Это макросы Аскольда Волкова
Вспомнил еще один вариант:
Если макрос состоит из нескольких выражений (#define SOME_MACRO bla(); bla();), то нужно обернуть в {}.
Но в данном случае это не так (всего одно выражение), и разворачивать его в блок совсем не обязательно.
> впервые слышу, быть может это конечно и оправданно.
Я видел в нескольких code style стандартах.
В том числе и гугловском.
> Силился представить, когда мне понадобится такая конструкция, но не смог…
Ну к примеру есть 4 порта — 2 набора команды/данные для 2х внешних устройств.
Выясняем при конфигурации к какому набору подрублено устройство, и пишем в переменную base_port, а к самим портам уже обращаемся через base_port + PORT_DATA и base_port + PORT_COMMAND. В компьютерном железе такое не редкость. В МК думаю тоже бывает.
Вспомнил еще один вариант:
if (XXX)
SOME_MACRO();
Если макрос состоит из нескольких выражений (#define SOME_MACRO bla(); bla();), то нужно обернуть в {}.
Но в данном случае это не так (всего одно выражение), и разворачивать его в блок совсем не обязательно.
> впервые слышу, быть может это конечно и оправданно.
Я видел в нескольких code style стандартах.
В том числе и гугловском.
> Силился представить, когда мне понадобится такая конструкция, но не смог…
Ну к примеру есть 4 порта — 2 набора команды/данные для 2х внешних устройств.
Выясняем при конфигурации к какому набору подрублено устройство, и пишем в переменную base_port, а к самим портам уже обращаемся через base_port + PORT_DATA и base_port + PORT_COMMAND. В компьютерном железе такое не редкость. В МК думаю тоже бывает.
0
А вот и видео разрушителя с краном:
и экскаватора:
как говорил раньше — кран все-равно вибрирует, но это уже связано с конструкцией.
и экскаватора:
как говорил раньше — кран все-равно вибрирует, но это уже связано с конструкцией.
+1
Когда начал читать, думал все привода будут задействованы в одной модели на разные движения.
ЗЫ. Плата у вас красивая получилась. ЛУТ?
ЗЫ. Плата у вас красивая получилась. ЛУТ?
0
Хотели изначально сделать чтобы клешня у разрушителя открывалась, но в итоге не получилось и двигается только три модели машин.
Для изготовления плат давно уже использую ЛУТ.
Для изготовления плат давно уже использую ЛУТ.
0
Only those users with full accounts are able to leave comments. Log in, please.
Управление несколькими сервоприводами с высокой точностью на МК ATmega16