roboforum.ru

Технический форум по робототехнике.

Управление Сервами в WinAvr

Ответить

avr123.nm.ru » 15 авг 2006, 18:06

Lirzman писал(а):На осциллографе сигнал такой формы(PB0):
______  _____   _____
|         |  |        |  |         |
|20мс |_|20мс |_|20мс |



чето первернутый он у вас.

aesok » 15 авг 2006, 18:12

Пока мелкие замечания.

volatile long int gangle; - Не нужен long (32 бита), хватит int (16).

char gservo;//Номер сервы - на всякий случай тоже лучше сделать volatile. Сделай оптимизацию -Os  и проверь работает программа или нет.

TCNT1 = period;  //настроить таймер на задежку (20) ms

Период- это длительность и 1 и 0. Тоесть P = t1 + t0.  

Код: Выделить всёРазвернуть
   |t1 | t0 |   

___|---|____|--------|_______

  |<- P  ->|


t1 у тебя равно gangle, следовательно t0 = period - gangle

Так что должно быть TCNT1 = period - gangle;

На осцилографе от начала одного импульса до начала следуещего должно быть 20 мс. (Будет небольшая ошибка, почему и как избежать, обьясню попозже.)

Анатолий.

aesok » 15 авг 2006, 18:24

Еще.

1.

SIGNAL(SIG_OVERFLOW1)
{
 >>>> PORTB CLR_B(gservo);//Выставить 0 на ножку    <<<<<
.......

Это не правильно выкинь.

2.

void timer1_init()
{
......
if(cur_state==1)
{TCCR1B =0x02;}
else
{
TCCR1B =0x01; //Старт таймера при делителе = 1024
//Биты CS10 CS11 CS12
}

}


Условие не нужно. Просто настрой таймер как тебе нужно.

удали гобьльную переменную cur_state; и добавь локальную статическую в обработчик прерывания.

SIGNAL(SIG_OVERFLOW1)
{
  static int cur_state = 0;
.....


Значение локальных статических переменных сохраняеться между вызовами функции.

Анатолий.

Lirzman » 15 авг 2006, 18:50

aesok писал(а):Условие не нужно. Просто настрой таймер как тебе нужно.
Удали голобальную переменную cur_state; и добавь локальную статическую в обработчик прерывания.

Я её глобальной сделал потому что управляющий импульс использует  делитель 0x01(TCCR1B) а 20мс импульс - (0x02).
Поэтому без условия не обойтись,
Код: Выделить всёРазвернуть
if(cur_state==1)//Импульс 20мс
{TCCR1B =0x02;}
else //управляющий импульс
{
TCCR1B =0x01; //Старт таймера при делителе = 1024
//Биты CS10 CS11 CS12
}


Можно конечно перевести 20мс задержку под делитель 1, только от перемены мест слагаемых сумма не меняется :D

aesok » 15 авг 2006, 19:07

Lirzman писал(а):Я её глобальной сделал потому что управляющий импульс использует  делитель 0x01(TCCR1B) а 20мс импульс - (0x02).
Поэтому без условия не обойтись,
Код: Выделить всёРазвернуть
if(cur_state==1)//Импульс 20мс
{TCCR1B =0x02;}
else //управляющий импульс
{
TCCR1B =0x01; //Старт таймера при делителе = 1024
//Биты CS10 CS11 CS12
}


Можно конечно перевести 20мс задержку под делитель 1, только от перемены мест слагаемых сумма не меняется :D


Да но тогда и в прерывании тоже нужно пеключать делитель
Код: Выделить всёРазвернуть
  if(cur_state == 0) {
    >>>>> TCCR1B =0x01; <<<<<<
    //вывести '1'
    TCNT1=gangle; //настроить таймер на задежку t ms
    PORTB SET_B(gservo);//Выставить 1 на ножку
    cur_state = 1;
   
 } else
 {
     //вывести '0'
>>>> {TCCR1B =0x02;} <<<<

      TCNT1 = period;  //настроить таймер на задежку (20) ms
     PORTB CLR_B(gservo);//Выставить 1 на ножку
     cur_state = 0;
 }


Это плохо, лучше использовать делитель на 2 всегда. Так проще. А потеря в точнсти не большая.

Анатолий.


Анатолий.

Lirzman » 15 авг 2006, 19:10

+0.25 гр набегало, теперь не набегает :D, но как-то странно все работает
при подаче одинакового импульса(60000) сервы становятся в два положения -  или +2.17 или +2.22(странно).
Чем дальше от центрального положения тем точнее всё работает:shock:
даже серву номер 1 при ~+50гр колбасит в диапазоне в +-0.1гр.

Одно я непонял:почему первая серва становится в положение +90гр
СРАЗУ после начала работы контроллера?

Как МНЕ кажется, т.к таймер начинает работать сразу(до присваивания переменным gangle,gservo чего-либо)он берет крайние значения(0,0)
соответственно передвигает первую серву на 0 - далеко за +90гр

Lirzman » 15 авг 2006, 19:12

С первой сервой я разобрался :D

За что отвечает параметр -Os?
Скомпилил с ним, но эффекта -0.
Всмысле ни хуже ни лучше. :D

avr123.nm.ru писал(а):точно померить сигналы можно при выводе их с помощью инструментов "ГРАФ" в PROTEUS

Что еще за "ГРАФ"?
По английйски как он называется?
А то чувствую что все мои беды из-за 20мс сигнала:?

aesok » 15 авг 2006, 19:31

Lirzman писал(а):С первой сервой я разобрался :D

ЗЫ за что отвечает параметр -Os?
Скомпилил с ним, но эффекта -0.
Всмысле ни хуже ни лучше. :D


Код должен быть меньше и быстрее.

Серва управляется только из обработчика прерывания. поэтомуиз
Код: Выделить всёРазвернуть
//************ПРОЦЕДУРА ПОЗИЦИОНИРОВАНИЯ СЕРВЫ********************
void Pos(char servo,long int angle)
{

PORTB SET_B(servo);//Выставить 1 на ножку
gservo=servo;//Номер сервы
gangle=angle;//Управляющий импульс
//TCNT1=gangle;//Управляющий импульс

}


убери 'PORTB SET_B(servo);//Выставить 1 на ножку'.

Функция Pos устанавливает переменую  gservo а обработчик таймера изходя из значения этой переменной формирует периодический сигнал который подается на серву.

Еще. чтобы серва удерживала положение ей не нужно подать один импульс длительностью 1.6+\-0.7мс, а нужно подовать этот импульс постоянно с периудом 20мс. Симулятор же вводит тебя в заблуждение, ему достаточно только одного импульса чтобы установить положение сервы. Поэтому сейчас более важен осцилограф чем модель сервы.

И еще Мы учимся пока управлять только ОДНОЙ серврой. Других пока нет.

Анатолий.

avr123.nm.ru » 15 авг 2006, 19:34

Lirzman писал(а):Что еще за "ГРАФ"?
По английйски как он называется?


в курсе по PROTEUS

http://proteus123.narod.ru/01.htm

на желтом фоне выделено - цитата:

"В SAMPLES\Simulation есть примеры использования самого мощного средства графического сбора и отображения данных
моделирования работы устройства :  

Simulation Graph

попробуйте вот эти примеры: DAC0808.DSN  или  Invosc.DSN

Откройте пример, запустите и приостановите симуляцию "

...  ну и дальше что да как.

aesok » 15 авг 2006, 19:36

void Servo_Control()
....
char szInput [4];
.....

szInput[0] = USART_Receive();
szInput[1] = USART_Receive();
szInput[2] = USART_Receive();
szInput[3] = USART_Receive();
szInput[4] = USART_Receive();
//szInput[5] = 0; // Строка должна заканчиваться 0

angle = atoi (szInput);

Длина масива должна быть 5 а последний элемент масива 0! Строки в С заканчиваются 0 ! Нельзя здесь заниматься оптимизацией! Почитайте о строках смволах в С. А пока пожалуйста делайте как я вам посоветовал.

Анатолий.
Последний раз редактировалось aesok 15 авг 2006, 19:47, всего редактировалось 1 раз.

Lirzman » 15 авг 2006, 19:42

aesok писал(а):нужно подавать этот импульс постоянно с периудом 20мс

Методом научного тыка, я это уже выяснил. :D

avr123.nm.ru писал(а):попробуйте вот эти примеры: DAC0808.DSN  или  Invosc.DSN

Уже пробую

avr123.nm.ru » 15 авг 2006, 19:48

aesok писал(а):t1 = 1.6+\-0.7мс


лучше 1.5 ...

aesok » 15 авг 2006, 19:56

avr123.nm.ru писал(а):
aesok писал(а):t1 = 1.6+\-0.7мс


лучше 1.5 ...


Да: 1.5+\-0.7мс

http://www.hitecrcd.com/Support/Faqs/Faq_Genservo_.htm

Анатолий.[/url]

Lirzman » 15 авг 2006, 20:03

А можно сделать симуляцию ГРАФОМ во время главной симуляции(когда  МК работает)?
Просто таймер начинает отсчитывать 20мс после приёма инфы с терминала :(

aesok » 15 авг 2006, 20:16



И Еще насчет точности сервомашинки. У сервомашинок есть параметр deadband или "мертвая зона". Если длительность управляющего умпульса изменилась не величину меньшую deadband  то серва на это изменение не реагирует. Эта величина равна 1..8мкс.

Код: Выделить всёРазвернуть
Q. What is servo deadband?
A. Deadband reflects the time it takes for a servo to respond when stick movement is given. Standard servos have a deadband of around 8us and high performance servos have a deadband of 1~3us.


Тоесть для стандортрной сервомашинки точность установки равна примерно 1%. И все десятые и сотые доли градуса поворота сервомашинки это извращения писателей симуляторов.

Подробнее про  "мертвую зону" почитайте здесь.
http://www.rcdesign.ru/articles/radio/servo_intro

Анатолий.[/code]


Rambler\'s Top100 Mail.ru counter