Технический форум по робототехнике.
Askar » 03 мар 2013, 20:32
Ребята помогите с MG995, как подобрать алгоритм поворота угла для MG995.
Не как не могу заставить её повернуться на 45, 60, 90, 180 градусов
Везде по разному... А нужно как на картинке:
как на картинке:
![bdb7ffd975.jpg (39.8 КиБ) Просмотров: 8230 bdb7ffd975.jpg](./download/file.php?id=27286&t=1&style=9&sid=035a0dc023e631a5a5c36c525eb9cc4b)
- Код: Выделить всё • Развернуть
#include <stdio.h>
#include <stm32f4xx.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_tim.h>
#include <stm32f4xx_exti.h>
#include <misc.h>
#include <stm32f4xx_syscfg.h>
volatile int servo_angle[4] = { 0, 0, 0, 0 }; // +/- 90 degrees, use floats for fractional
int main(void)
{ SystemInit(); // 25 MHz
// Servo min(1ms) = 1580
// Servo max(2ms) = 3160
//TIM_SetCompare1(TIM1, 1580); // 1580 = 1.0ms
//TIM_SetCompare1(TIM1, 2370); // 2370 = 1.5ms
//TIM_SetCompare1(TIM1, 3160); // 3160 = 2.0ms
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
// TIM1 clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// GPIOE clock enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
// TIM1 channel 2 pin (PE.9) configuration
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
// Connect TIM pins to AF2
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1);
TIM_TimeBaseStructInit (&TIM_TimeBaseStructure);
//TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/5000000; // pers 33.6
//TIM_TimeBaseStructure.TIM_Period = 31600; // 20ms for servo period
//TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 100000 - 1;
//TIM_TimeBaseStructure.TIM_Period = 2000;
TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1; // 24 MHz / 24 = 1 MHz
TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20 ms)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1 , &TIM_TimeBaseStructure);
// PWM1 Mode configuration: Channel1
// Edge -aligned; not single pulse mode
TIM_OCStructInit (& TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 600 + 900;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1 , &TIM_OCInitStructure);
TIM_BDTRInitTypeDef bdtr;
TIM_BDTRStructInit(&bdtr);
bdtr.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &bdtr);
// Enable Timer Interrupt and Timer
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //
TIM_Cmd(TIM1 , ENABLE);
//TIM_SetCompare1(TIM1, 1500); // 1580 = 1.0ms = 0
//delayMS(1*100);
//TIM_SetCompare1(TIM1, 2160); // 2370 = 1.5ms = 90
//delayMS(1*100);
//TIM_SetCompare1(TIM1, 3460); // 3160 = 2.0ms = 180
//delayMS(1*100);
uint8_t i;
for (i=0;i<=90;i++)
{
//delayMS(100);
set_pos(i);
}
while (1)
{
}
return 0;
}
#define SERVO_180 3160
#define SERVO_0 1500
// Функция устанавливает позицию вала (в градусах)
void set_pos(uint8_t pos)
{
uint32_t tmp=(SERVO_180 - SERVO_0) / 90 ;
uint32_t tmp2 = SERVO_0 + tmp * pos;
TIM_SetCompare1(TIM1, tmp2);
}
void delayMS(uint32_t ms)
{
ms *= 3360;
while(ms--)
{
__NOP();
}
}
// Функция задержки
void delay(void)
{
volatile uint32_t i;
for (i=1; i != 0xFFFF; i++);
}
dccharacter » 03 мар 2013, 20:36
А в чем проблема? Ошибка на градус-два или вообще не работает?
Askar » 03 мар 2013, 21:14
Работает, ошибка в градусах. Я уже разные алгоритмы перепробовал... но не один не дает точных (хотя бы с погрешностями) результаты.
К сожалению у меня нет осциллографа по этому точно не знаю как проходят импульсы.
Мне нужна функция, которой я буду задавать градусы а она будет крутить привод на необходимый угол. Как на картинке.
Сейчас же, я не знаю какие значения подобрать для TIM_SetCompare1(TIM1, tmp);
Как настроить таймер, есть примеры (ниже) но какой из нужен?
//TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/5000000; // pers 33.6
//TIM_TimeBaseStructure.TIM_Period = 31600; // 20ms for servo period
//TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 100000 - 1;
//TIM_TimeBaseStructure.TIM_Period = 2000;
TIM_TimeBaseStructure.TIM_Prescaler = 24 - 1; // 24 MHz / 24 = 1 MHz
TIM_TimeBaseStructure.TIM_Period = 20000 - 1; // 1 MHz / 20000 = 50 Hz (20 ms)
Добавлено спустя 1 минуту 50 секунд:
задаю 1500, он у меня крутится на 25 градусов, 2000 - на 45 градусов
dccharacter » 03 мар 2013, 21:59
надо выяснить, на какой частоте шарашит камень. возможно на максимуме 168МГц
тебе надо сделать так, чтобы 16 битный таймер с максимальным разрешением работал с периодом 20 мс
я обычно считаю так:
20мс = 60000 (немного с запасом, 60 тысяч понятно откуда беруться?)
т.е. один тик должен быть 20000мкс/60000 ~= 0.33 мкс.
Тогда прескейлер должен быть 168*0.33 ~=56.
Уточняем, с прескейлером 56 частота клока таймера будет 3МГц, а длительность тика одного ~0.33мкс
Для того, чтобы получить период 20мс, устанавливаем период равным 20000/0.33 (или 3000000/50) = 60000
Теперь значения пульса у тебя будут от 3000 (1мс) до 6000(2мс)
Так понятно?
Askar » 04 мар 2013, 06:03
Я посмотрел в даташит, там указано что таймер работает на 168, а ещё интерфейс счетчик работает на 84. А по другому можно узнать на какой частоте?
Откуда берутся 60 тыс? =)
Чу чуть понял, получается что бы мне провернуть на 90 градусов, я должен подать импульс длиной 4500?
А между сервами есть разница? т.е. если я скажем имею три разных серв (от разных производителей), они себя будут по разному ввести? т. е.
dccharacter » 04 мар 2013, 06:57
Ничего ты не понял
Таймер 16-ти битный. т.е. он может досчитать до 65535, а потом переполнится (8-ми битный таймер, например, может досчитать только до 255, потом переполнение и снова с нуля начинает считать)
Тебе надо по-максимуму использовать высокое разрешение таймера, соответственно надо, чтобы за 20мс в идеале натикало 65535 тиков. Но предделители дробными не бывают, бывают только целыми, поэтому и надо взять достаточно большое число в диапазоне 0-65535, но чтобы предделитель был целым.
Пример: через 20мс значение таймера будет:
С предделителем 56: 20000*168/56 = 60000
С предделителем 55: 20000*168/55 = 61090
С предделителем 52: 64615
С предделителем 51: 65882 (а это уже больше, чем 65535, поэтому таймер никогда не сможет достигнуть этого значения)
Т.е. максимальный прескейлер, который ты можешь выбрать - 52 (ну, т.е. минимальный). Чем больше будет прескейлер, тем меньше тиков натикает за 20мс и тем меньше будет разрешение твоего таймера.
Это откуда беруться 60 тыс.
Дальше, на какой частоте работает таймер. Запускаешь отладку и смотришь значение переменной SystemCoreClock. Это и есть частота, на которой шарашит камень. Если она не 168, снова проводишь расчеты. Но это частота главной шины. Таймер сидит на какой-нибудь APB1(не помню). Эта другая шина может работать на более низкой частоте. Посмотреть, установлен ли делитель на эту шину. Хуже того, частота таймера может также делиться (т.е. для таймера устанавливается и делитель частоты, и предделитель). Тебе надо проверить все эти настройки, чтобы понять, на какой частоте шарашит таймер. После этого, если у тебя нет осцилла, я бы повесил на ногу светодиод, настроил переполнение таймера на (как мне кажется) 1с и проверил, что светодиод включается/выключается ровно раз в секунду. Если эжто происходит чаще/реже, какой-то из предделителей частоты пропущен.
Askar » 04 мар 2013, 16:50
Установил вот эти параметры, вроде лучше стало... Но градусах все равно ошибки ~10-20
TIM_TimeBaseStructure.TIM_Prescaler = 56;
TIM_TimeBaseStructure.TIM_Period = 60000;
Вот так кручу:
TIM_SetCompare1(TIM1, 1000); // 0 результат 0 градусов
delayMS(1*1000);
TIM_SetCompare1(TIM1, 1250); // 45 результат 15
delayMS(1*1000);
TIM_SetCompare1(TIM1, 1500); // 90 результат 25
delayMS(1*1000);
TIM_SetCompare1(TIM1, 1750); // 120 результат 45
delayMS(1*1000);
TIM_SetCompare1(TIM1, 2000); // 180 результат 60
delayMS(1*1000);
Как вернуть серву на начальную позицию?
elmot » 04 мар 2013, 18:00
ошибка 5 град, там где 90
Какие претензии?
Что есть начальная позиция? снова на устовный 0? тогда:
TIM_SetCompare1(TIM1, 1000); // 0 результат 0 градусов
Askar » 04 мар 2013, 18:21
Почему ошибка?
Претензий не каких.
dccharacter » 04 мар 2013, 22:33
Askar, a что такое '1000'?
Askar » 05 мар 2013, 05:51
1000 ms. =)
Ребята у кого есть под рукой STM32F4, СЕРВА(MG995) и осциллограф...
Помогите... Кому не лень накидать несколько строчек коду...
Angel71 » 05 мар 2013, 11:33
пока даже прошивку заливать бессмысленно. никто не обратил внимания, что тс считает за крайние положения 1000 и 2000?
Askar » 05 мар 2013, 12:12
На картинке указано 1000 и 2000
Angel71 » 05 мар 2013, 12:34
т.е. увидили в начеле статьи фотку сервы с наклейкой "mg995" и подумали "о! это про мою серву"? железная логика.
Askar » 05 мар 2013, 13:23
Неееееееее, просто прочитал пару десяток статей, и везде говорилось что стандарт 1000-2000.
Прошелся пару дней назад по данному форуму, заметил что у тебя тоже самая серва и боле того, тат же самый чип.
=)
По твоему сколько "мс" для левого и правого "мс"?
Если есть чем помочь,буду благодпрен>