roboforum.ru

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

AXON и управление сервами [из Хексапод - как минимизировать

Программирование микроконтроллеров AVR, PIC, ARM.
Разработка и изготовление печатных плат для модулей.

AXON и управление сервами [из Хексапод - как минимизировать

Сообщение romick » 10 июн 2010, 13:59

=DeaD= писал(а):Какую точность оно у вас даёт? Плавные движения уже реализовали? Без них будет полный кирдык :)

Надеюсь что реализовал :D Пока сервы не получу на руки, могу только предполагать. Приращения скорости использую пока линейные. Проще наверно исходники показать, чем сто раз объяснять :) Сразу предупреждаю, баги присутствуют, код в процессе разработки.
Код: Выделить всёРазвернуть
//attempt at using the Axon and Axon II as a servo controller


//define how data should be sent (choose only one)
//#define U0
#define USB

//declare microcontroller
//#define AXON
#define AXON2

#define DEBUG


//WebbotLib Includes
#ifdef AXON
   #include "sys/axon.h"
#endif
#ifdef AXON2
   #include "sys/axon2.h"
#endif

//#include "buffer.h"
#include "iopin.h"      
#include "timer.h"      
#include "rprintf.h"   //use for UART
#include "inttypes.h"


//UART defines (name your UART)
#define U0_UART UART0
#define USB_UART UART1
//UART baud defines (change baud rate)
#define U0_BAUD (BAUD_RATE)230400
#define USB_BAUD (BAUD_RATE)230400
//UART define which uart to use
#define U0_ACTIVATE &uart0SendByte
#define USB_ACTIVATE &uart1SendByte
//getting data
#define GET_DATA_U0 uart0GetByte()
#define GET_DATA_USB uart1GetByte()


//create a big buffer for UART
#ifdef U0
   #define UART0_RX_BUFFER_SIZE 100
#endif
#ifdef USB
   #define UART1_RX_BUFFER_SIZE 100
#endif

#include "hardware.h"   //declare your servo and sensor ports here


int8_t lastByte=-1;         //store last recieved character
//lastByte = -1;
int8_t buff_array[100];   //store last command
uint8_t buff_pos=0;      //record current position in array
uint8_t buff_read=0;   //record current position in array
boolean command_received=0;   //active last command
SERV *serva[32];

int count_us;
enum command_state commst=empty;


void save_move(uint8_t *channel, uint16_t *pulsewidth, uint16_t *speed, uint16_t *time)
{
   if (*pulsewidth)
   {
      for(int i=0; i<32; i++)
      {
         if (serva[i]->channel == *channel)
         {
            if (*time)
            {
               long int tbs;
               if (serva[i]->target > serva[i]->posnow)
               {
                  tbs = (serva[i]->target - serva[i]->posnow) / *time * 1000;
               } else {
                  tbs = (serva[i]->posnow - serva[i]->target) / *time * 1000;
               }
               if (tbs < *speed)
               {
                  *speed = tbs;
               }
            }
            serva[i]->target = *pulsewidth;
            serva[i]->speed = *speed;
            rprintf("Parsed command: channel %d, target %d, speed %d,\n", *channel, *pulsewidth, *speed);
         }
      }
      *channel=0;
      *pulsewidth=0;
      *speed=0;
   }
}


//initialize hardware, ie servos, UART, etc.
void appInitHardware(void)
{

   #ifdef AXON2
      led_off();
   #endif
      
   //setup UART0 or USB
   #ifdef USB
      uartInit(USB_UART, USB_BAUD);
      rprintfInit(USB_ACTIVATE);
   #endif
   #ifdef U0
      uartInit(U0_UART, U0_BAUD);//bluetooth
      rprintfInit(U0_ACTIVATE);
   #endif
   
   for (int i; i<32;i++) //init servo data
   {
      //serva[i] = &(SERV);
      serva[i]->channel = i;
      serva[i]->target = 1500;
      serva[i]->posnow = 1500;
      serva[i]->speed = 0;
   }
   
}


TICK_COUNT appInitSoftware(TICK_COUNT loopStart)
   {
   rprintf("init\n");
   count_us = clockGetus();
   return 0;
   }

   
// This is the main loop
TICK_COUNT appControl(LOOP_COUNT loopCount, TICK_COUNT loopStart)
   {
   ////////////GET COMMAND/////////////
   #ifdef USB
      lastByte=GET_DATA_USB;
   #endif
   #ifdef U0
      lastByte=GET_DATA_U0;
   #endif

   //fill up array with command recieved from UART
   if(lastByte!=-1)//has new data
   {
      buff_array[buff_pos]=lastByte;
      buff_pos++;

      if(lastByte == 0x0d)//if command is finished
         command_received=1;
   }

   //when command is received, parse it
   if(command_received)
   {
      uint8_t incoming_channel=0;
      uint16_t incoming_pulsewidth=0;
      uint16_t incoming_speed=0;
      uint16_t incoming_time=0;
      commst = empty;
      rprintf("Command received:");
      rprintfMemoryDump(buff_array, 0, buff_pos);
      rprintf("\n");
      //look for 'T' command first
      buff_read=0;
      while(buff_read <= buff_pos)
      {
         if (buff_array[buff_read] == 'T' || buff_array[buff_read] == 't')
         {
            commst = time;
         } else {
            if (commst == time)
            {
               incoming_time = incoming_time * 10 + (buff_array[buff_read] & 0x0F);
            } else {
               commst = empty;
            }
         }
         buff_read++;
      }
      
      //while the full array hasn't been read yet
      //parse the rest of commands
      buff_read=0;
      while(buff_read<=buff_pos)
      {
         if (buff_array[buff_read] > 0x2F && buff_array[buff_read] < 0x3A && commst )
         {
            switch (commst)
            {
               case channel:
                  incoming_channel = incoming_channel * 10 + (buff_array[buff_read] & 0x0F);
                  break;
               case pulsewidth:
                  incoming_pulsewidth = incoming_pulsewidth * 10 + (buff_array[buff_read] & 0x0F);
                  break;
               case speed:
                  incoming_speed = incoming_speed * 10 + (buff_array[buff_read] & 0x0F);
                  break;
               case time: case empty: case positionoffset:
                  break;
            }
         } else {
            switch (buff_array[buff_read])
            {
               case 0x0d:
                  save_move(&incoming_channel, &incoming_pulsewidth, &incoming_speed, &incoming_time);
                  break;
               case '#':
                  save_move(&incoming_channel, &incoming_pulsewidth, &incoming_speed, &incoming_time);
                  commst = channel;
                  break;
               case 'P': case 'p':
                  commst = pulsewidth;
                  break;
               case 'S': case 's':
                  commst = speed;
                  break;
               case 'T': case 't':
                  commst = empty;
                  break;
               default:
                  commst = empty;
            }
         }
         buff_read++;
      }
      buff_pos=0;//reset array
      command_received=0;
   }

   
   // send pulses to servos every 18 ms
   if (clockHasElapsed(count_us, 18000))
   {
      count_us = clockGetus();
      rprintf("Time is: %d\n", count_us);
      
      //define short-term target for each servo
      long int pos = 0;
      for (int i; i<32;i++)
      {
         pos = serva[i]->posnow;
         if (serva[i]->target > pos)
         {
            pos += serva[i]->speed/50;
            if (pos > serva[i]->target) pos = serva[i]->target;
         }  else {
            pos -= serva[i]->speed/50;
            if (pos < serva[i]->target) pos = serva[i]->target;
         }
         serva[i]->posnow = pos;
      }
      //sort servos ascending by short-term target
      int isDone=0;
      SERV *tmp;
      for (int i=0;(i<32-1)&&(!isDone);i++)
      {
         isDone=1;
         for (int j=0;j<32-i-1;j++)
         {
            if (serva[j]->posnow > serva[j+1]->posnow)
            {
               // keep number and port in sync with the position so we know which port to change!
               tmp = serva[j];
               serva[j] = serva[j+1];
               serva[j+1] = tmp;

               isDone=0;
            }
         }
      }
      //*tmp = 0;
      
      #ifdef DEBUG
      for (int i; i<32;i++)
      {
         rprintf("Servo state: order: %d, channel: %d, target: %d, posnow: %d, speed: %d", i, serva[i]->channel, serva[i]->target, serva[i]->posnow, serva[i]->speed);
      }
      #endif
      cli(); //block interrupts
      
      // put all servos' pin to high
      for (int i; i<32;i++)
      {
         pin_high(serva[i]->pin);
      }
      
      // put pins low based on short-term target
      int offset=0;
      for (int i=0;i<32;i++)
      {
         pos = serva[i]->posnow;
         if (pos > 0)
         {
            if (pos > offset)
            {
               // wait until this servo's position offset
               delay_us(pos - offset);
               offset = pos;
            }
            // turn off this servo and continue with next servos
            pin_low(serva[i]->pin);
         }
      }
      
      
      sei(); //unblock interrupts
   }



   return 0;
   }


=DeaD= писал(а):Нет, нет и еще раз нет :) мы можем продавать изделие как пообещали за 1700р. А можем не заморачиваться с поиском правильных подрядчиков, переговорами, выбором поставщиков материала и компонент и продавать набор за 3000р с маржой 5% :)

При любых расчетах в экономике подразумевается, что целью хозяйствующего субъекта является максимизация извлечения прибыли. И чтобы у вас был покупатель, вы будете вынуждены искать пути снижения себестоимости. Иначе покупатель предпочтет конкурентный товар (в данном случае самостоятельное изготовление). Но это все конечно чисто теоретически.
=DeaD= писал(а):А гадать есть что, у нас с ними разная входящая себестоимость была на один и тот же товар. Но цены по которым мы отпускали товар в свой магазин и к ним были одинаковые :)
Фишка в том, что они неправильно управляли запасами и товар у них лежал по 3 месяца. А цены на компьютерную технику имеют свойство снижаться достаточно быстро.

Это же я и говорил про входящую себестоимость, только другими словами. Себестоимость товара при прочих равных условиях определяется обычно 2 факторами: объемами закупок и каналом поставки. А затраты на управление запасами уже определяют размер коммерческих расходов. На рынке робототехники пока вроде нет признаков "рынка компьютеров". Предлагаю свернуть тему ценообразования, потому что мы уже от основной мысли ушли.

=DeaD= писал(а):Комплект механики без серв для шестинога на базе HXT900.

А когда ожидать на базе стандартных серв?
Последний раз редактировалось Vooon 10 июн 2010, 19:17, всего редактировалось 1 раз.
Причина: [code=cpp]!!!
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение =DeaD= » 10 июн 2010, 14:13

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

Это очень теоретически :) покупатель предпочтет конкурентный товар при некотором уровне цены независимо от нашей себестоимости и маржи :) вот если мы потратили 3 дня своего времени, провели переговоры и нашли где брать подшипники за 10р/шт - почему мы должны подарить своё время кому-то просто так? Для нас какой резон тогда бегать? Так что вопрос маржи - это всего лишь вопрос добавленной стоимости товара, которую мы генерим - если у нас маржа 1000% и все выбирают нас, значит мы буквально из ничего делаем конфетку и всех это устраивает. А смотреть надо на то, что мы предлагаем и за какие деньги :) а делаем мы это сами или заказываем где-то и относим ли на себестоимость - вопрос десятый.

Добавлено спустя 1 минуту 10 секунд:
romick писал(а):А когда ожидать на базе стандартных серв?

Хороший вопрос, попробую на днях нашарить 3 шт HXT12k из старых запасов и собрать одну ногу. Если всё ок - значит будем считать что почти готовы чертежи и надо собирать прототип как только ко мне придет посылка с 20 сервами.

Добавлено спустя 3 минуты 28 секунд:
romick писал(а):Надеюсь что реализовал :D Пока сервы не получу на руки, могу только предполагать. Приращения скорости использую пока линейные. Проще наверно исходники показать, чем сто раз объяснять :) Сразу предупреждаю, баги присутствуют, код в процессе разработки.

Не будет работать - вы потеряете всю инфу из UART'а, потому как заблокировали прерывания при выдаче сигналов на сервы.
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение romick » 10 июн 2010, 14:45

{игнорирую аргументы оппонента на экономическую тематику}
=DeaD= писал(а):Не будет работать - вы потеряете всю инфу из UART'а, потому как заблокировали прерывания при выдаче сигналов на сервы.

А иначе будут дрожания сервы, потому как прерывания будут изменять длину импульса. Проблему можно решить на стороне, отсылающей команду, - после отправления команды ожидать контрольную сумму команды, при отклонении - пересылать команду еще раз. Пока буду смотреть, как реализовано у SSC-32.
Кстати, делалось на базе другой прошивки, которая, я так понимаю, успешно работает. http://www.roborealm.com/downloads/Axon ... ler_II.zip
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение =DeaD= » 10 июн 2010, 14:52

romick писал(а):А иначе будут дрожания сервы, потому как прерывания будут изменять длину импульса.

Если реализовывать без специального железа - именно так и будет.

Вот только проблема в том, что программы разработанные для SSC-32 ничего не знают про ваши игры с таймерами и контрольные суммы, поэтому они тупо не будут работать при таком подходе :(
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение romick » 10 июн 2010, 15:08

А где можно посмотреть, как это реализовали в ORC-32? Не спасет ли ситуацию хардварный UART и буфер для него? Особенно с учетом того, что прерывания блокируются на 2 мс (за это время вроде может поступить около 30 байт при скорости 115кбит)? Есть вариант повесить код, ответственный за формирование импульса на таймер, как думаете?
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение =DeaD= » 10 июн 2010, 15:11

У нас совершенно по другому организована генерация импульсов на контроллере - через аппаратные ШИМ-генераторы и внешние счетчики. Читать тут метод 4.5 - [[Управление сервами с МК]]. Мы специально это делали в железе, чтобы в программе никаких проблем не иметь.

Добавлено спустя 35 секунд:
Вешать код формирования имульсов на таймер можно, только точность там средняя.
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение romick » 10 июн 2010, 15:17

У вас получается 32 ШИМ-генератора? Для каждой сервы ведь может быть свой импульс.
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение setar » 10 июн 2010, 15:20

:) для того чтобы сделать 32 ШИМ не требуется 32 генераторов
требуется 32 счётчика которые показывают на каких ногах шим находится в состоянии 1 и сколько ему ещё таковым оставаться.
Аватара пользователя
setar
Site Admin
 
Сообщения: 10989
Зарегистрирован: 04 окт 2004, 12:58
Откуда: St.Petersburg
Skype: taranenko.sergey
ФИО: Сергей Тараненко

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение =DeaD= » 10 июн 2010, 15:22

romick писал(а):У вас получается 32 ШИМ-генератора? Для каждой сервы ведь может быть свой импульс.

У нас 4 ШИМ-генератора переключающих 4 счетчика по 8 серв на каждом.
Проект [[Open Robotics]] - Универсальные модули для построения роботов
Аватара пользователя
=DeaD=
 
Сообщения: 24218
Зарегистрирован: 06 окт 2004, 18:01
Откуда: Ебург
прог. языки: C++ / PHP / 1C
ФИО: Антон Ботов

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение Michael_K » 10 июн 2010, 15:24

Про метизы... (сетару м.б. интересно будет)
у меня рядом с домом магазинчик где поштучно по смешным ценам
продаются винты, гайки и т.п. от полутора мм... в наличии вроде есть.

(ну то есть килограммами наверное еще смешнее, но и так неплохо)
Аватара пользователя
Michael_K
 
Сообщения: 6028
Зарегистрирован: 07 окт 2009, 00:29
Откуда: СПб

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение romick » 10 июн 2010, 15:42

Возвращаясь к Axon'у - у него аппаратный ШИМ реализован только на 12 ногах, что для шестинога недостаточно. Вопрос: в Axon'е на каждом ШИМе - только 3 ноги, вы говорите о 8. Если ли объективные факторы,которые могут препятствовать тому чтобы вешать на каждый ШИМ по 8 ног?
Возвращаясь к ORC-32 - на каких OR-модулях эта прошивка работает и поддерживает ли она полностью набор команд SSC-32?
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение Grem » 10 июн 2010, 15:53

2romick, OR-AVR-M128-S
"There is nothing better than sliding down snow and flying through the air" (с) Shane McConkey.
Lieber ein Brett am Fuß als eins vorm Kopf, aber lieber ein Brett vorm Kopf als zwei am Fuß.
Аватара пользователя
Grem
 
Сообщения: 1530
Зарегистрирован: 16 май 2009, 12:50
Откуда: Россия
прог. языки: Java, C

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение blindman » 10 июн 2010, 16:29

romick писал(а):Вопрос: в Axon'е на каждом ШИМе - только 3 ноги, вы говорите о 8

Один выход таймера МК управляет одним внешним счетчиком с 8 выходами.
Проект [[Open Robotics]] - универсальные модули для построения роботов
Модули Open Robotics можно приобрести в магазине shop.roboforum.ru

Day OFF? You must be pulling my leg! Stop making humor before someone sees you, fool!

Аватара пользователя
blindman
 
Сообщения: 4130
Зарегистрирован: 29 апр 2008, 21:15
Откуда: Хабаровск
прог. языки: C,C++,Assembler,PHP,Javascript,Ruby, SPIN,Java(?)
ФИО: Андрей Юрьевич

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение romick » 10 июн 2010, 16:39

Не, я конечно тугодум, и ни разу не технический специалист, но я понял как реализован аппаратный ШИМ в ORC-32. Что я не могу понять, это почему автор Axon'а не поставил внешние счетчики с 8 выходами, а только с 3-мя. Вдруг на это у него какая-то причина была...
romick
 
Сообщения: 13
Зарегистрирован: 24 май 2010, 12:09
Откуда: Липецк
прог. языки: python, perl

Re: Хексапод - как минимизировать - собираем идеи :)

Сообщение blindman » 10 июн 2010, 16:44

Наверно не понял все-таки. Потому что в этом аксоне нету внешних счетчиков. Совсем. Ни с тремя, ни с 8, ни с 1000 выходами. Там тупо голый контроллер с минимальной обвязкой.
Проект [[Open Robotics]] - универсальные модули для построения роботов
Модули Open Robotics можно приобрести в магазине shop.roboforum.ru

Day OFF? You must be pulling my leg! Stop making humor before someone sees you, fool!

Аватара пользователя
blindman
 
Сообщения: 4130
Зарегистрирован: 29 апр 2008, 21:15
Откуда: Хабаровск
прог. языки: C,C++,Assembler,PHP,Javascript,Ruby, SPIN,Java(?)
ФИО: Андрей Юрьевич

След.

Вернуться в Микроконтроллеры

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14