Автоповороты Servo и Ручные повороты Servo
- Войдите на сайт для отправки комментариев
Нужна помощь, переделываю напольный вентилятор, всё ОК, кроме одного момента с Servo.
Есть 2 функции:
- первая отвечает за плавные ручные повороты Servo влево-вправо на заданные углы при зажатии кнопки на ИК пульте;
- вторая отвечает за автоповороты влево-вправо на те же заданные углы при одинарном нажатии кнопки и выключении при нажатии другой кнопки.
Обе функции работают и плавно поворачивают Servo, но не могу побороть проблему:
Если включаем автоповороты, Servo ходит туда-сюда, останавливает, серва запоминает положение, всё классно. Но когда зажимаю кнопку ручных поворотов влево или вправо (естественно при выключенных автоповоротах), то Servo резко возвращается на угол при котором остановилась Servo в автоповоротах.
Как подозреваю, это происходит из-за несоответствия углов после преобразования функции map().
Нужно что бы вручную повернул на определённый угол и включил автоповороты, Servo пошла крутится от последнего положения. Выключил автоповороты, зажал кнопку влево или вправо, Servo так же медленно начала продолжать вращение в нужную сторону.
Оставил в коде только относящееся к поворотам для общего понимания.
Нужные 2 функции вывел под отдельный спойлер:
//Функция для Автоповоротов Servo
void auto_Rotation() {
if (millis() - tmr_auto >= AUTO_DELAY_TIME_SERVO) { // Если время больше или равно "AUTO_DELAY_TIME_SERVO", тогда...
tmr_auto = millis(); // записываем время в "tmr_auto"
auto_val += dir; // Прибавляем "auto_val" значение градуса "dir"
if (auto_val >= RIGHT_CORNER || auto_val <= LEFT_CORNER) dir = -dir; // Разворачиваем в обратную сторону
rotation.write(auto_val); // Записываем угол в Servo
}
}
//Функция для ручных поворотов Servo (влево - вправо при удержании кнопки)
void manual_Turns() {
if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO) (Right_Turns = false), (Left_Turns = false); // Если вермя больше "TURNS_DELAY_TIME_SERVO", тогда опускам флаги
if (Right_Turns == true && transformation <= MAX_VALUE) transformation += counter; // Если правый флаг поднят и значение "transformation" меньше "MAX_VALUE", то производим инкремент счётчика
if (Left_Turns == true && transformation >= MIN_VALUE) transformation -= counter; // Если левый флаг поднят и значение "transformation" больше "MIN_VALUE", то производим декремент счётчика
auto_val = constrain(auto_val, LEFT_CORNER, RIGHT_CORNER); // Ограничим диапазон для безопасности от "LEFT_CORNER" до "RIGHT_CORNER"
auto_val = map(transformation, MIN_VALUE, MAX_VALUE, LEFT_CORNER, RIGHT_CORNER); // Задаём диапазон скорости и поворота Servo (углы поворота от "LEFT_CORNER" до "RIGHT_CORNER" градусов)
rotation.write(auto_val); // Записываем положение в Servo
}
Почти полный код (для понимания), вырезал всё лишнее:
//Servo (pin)
#define SERVOMOTOR 9 // pin для подключения Servo
//Прерывания (pin)
#define INTERRUPT_PIN_IR 2 // Пин с прерыванием к которому подключён ИК приёмник
//Настройки для ручных и автоповоротов Servo
#define RIGHT_CORNER 130 // Задаём максимальный поворот на ПРАВЫЙ угол
#define LEFT_CORNER 12 // Задаём максимальный поворот на ЛЕВЫЙ угол
#define MAX_VALUE 20000 // Максимальное значение для задания скорости движения Servo при ручных поворотах
#define MIN_VALUE 0 // Минимальное значение для задания скорости движения Servo при ручных поворотах
#define AUTO_DELAY_TIME_SERVO 50 // Время повторений итераций(в миллисекундах) для автоповоротов. Чем больше время, тем медленее будут автоповороты
#define TURNS_DELAY_TIME_SERVO 100 // Время (в миллисекундах) после истечения которого опускаем флаги (если не поступил новый сигнал) при ручных поворотах Servo
#include <SoftServo.h> // Библиотека для программного управления Servo (на базе millis/micros)
#include <NecDecoder.h> // Лёгкая библиотека для декодирования ИК протокола NEC
//Коды кнопок пульта в HEX
#define IR_UP 0x1 // Кнопка вверх: ↑ Авто - Вращения Вкл.
#define IR_DOWN 0x81 // Кнопка вниз: ↓ Авто - Вращения Выкл.
#define IR_LEFT 0x8A // Кнопка <: « Влево
#define IR_RIGHT 0xB2 // Кнопка >: Вправо »
SoftServo rotation; // Создаём Объект для Sertvo
NecDecoder ir; // Создаём Объект для ИК приёмника
//Автоповороты Servo
int auto_val = 0;
int dir = 1; // Градус поворота для каждой итерации функции
bool auto_RotatON = false; // Если "true", то включаем автоповороты Servo
uint32_t tmr_auto; // Последнее обновление времени (для автоповоротов Servo)
//Ручные повороты Servo
int transformation = 0; // Переменная для преобразования ручных поворотов через map()
int counter = 1; // Увеличиваем перемещение на каждом шаге для ручных поворотов
bool RotatON = false; // Если "true", то включаем повороты Servo(влево - вправо)
bool Right_Turns = false; // Если "true", то поворачиваем вручную Servo вправо (при зажатии кнопки вправо)
bool Left_Turns = false; // Если "true", то поворачиваем вручную Servo влево (при зажатии кнопки влево)
uint32_t tmr_turn = 0; // Последнее обновление времени (для ручных поворотов Servo)
void setup() {
//Получение ИК сигнала через прерывания
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN_IR), irIsr, FALLING);
if (auto_val > RIGHT_CORNER || auto_val < LEFT_CORNER) auto_val = (RIGHT_CORNER - LEFT_CORNER) / 2; // Если считанный из EEPROM угол выходит за пределы заданных, то переводим серво в центральное положение от заданных углов
rotation.attach(SERVOMOTOR); // Вкл. Servo
rotation.delayMode(); // переключить в режим задержки (по умолчанию)
rotation.write(auto_val); // Записываем положение Servo из FRAM после включения питания
}
void loop() {
rotation.tick(); //Вызываем тикер для работы "SoftServo.h"
if (auto_RotatON == true) auto_Rotation(); // Запускаем функцию вкл. автоповоротов Servo
if (RotatON == true) manual_Turns(); // Иначе работает функция ручных поворотов Servo
ir_Decoder(); // Проверяем функцию "ir_Decoder()" на наличие приёма команд с ИК пульта
}
void irIsr() {
ir.tick(); // Вызывать при ОТРИЦАТЕЛЬНОМ (FALLING) фронте на пине ИК приемника в прерывании
//При удержании любой кнопки срабатывает прерывание и перехватываем пустой ИК сигнал, считаем его за код кнопки. При отпускании кнопки считаем, что код перестал приниматься
tmr_turn = millis(); // Записываем текущее время (для ручных поворотов Servo)
}
void ir_Decoder() {
//Получаем ИК коды
if (ir.available()) { // Если пакет успешно принят, то...
switch (ir.readCommand()) { // Читаем команду
case IR_UP:
//Кнопка вверх: ↑ Авто - Вращения Вкл.
RotatON = false; // Опускаем флаг для ручных поворотов
auto_RotatON = true; // Поднимаем флаг для Вкл. Автоповоротов
break;
case IR_DOWN:
//Кнопка вниз: ↓ Авто - Вращения Выкл.
RotatON = false; // Опускаем флаг для ручных поворотов
auto_RotatON = false; // Опускаем флаг для Автоповоротов
break;
case IR_LEFT:
//Кнопка <: « Влево
auto_RotatON = false; // Опускаем флаг для Автоповоротов
RotatON = true; // Поднимаем флаг для ручных поворотов
Right_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "« Влево"
break;
case IR_RIGHT:
//Кнопка >: Вправо »
auto_RotatON = false; // Опускаем флаг для Автоповоротов
RotatON = true; // Поднимаем флаг для ручных поворотов
Left_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "Вправо »"
break;
}
}
}
//Функция для Автоповоротов Servo
void auto_Rotation() {
if (millis() - tmr_auto >= AUTO_DELAY_TIME_SERVO) { // Если время больше или равно "AUTO_DELAY_TIME_SERVO", тогда...
tmr_auto = millis(); // записываем время в "tmr_auto"
auto_val += dir; // Прибавляем "auto_val" значение градуса "dir"
if (auto_val >= RIGHT_CORNER || auto_val <= LEFT_CORNER) dir = -dir; // Разворачиваем в обратную сторону
rotation.write(auto_val); // Записываем угол в Servo
}
}
//Функция для ручных поворотов Servo (влево - вправо при удержании кнопки)
void manual_Turns() {
if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO) (Right_Turns = false), (Left_Turns = false); // Если вермя больше "TURNS_DELAY_TIME_SERVO", тогда опускам флаги
if (Right_Turns == true && transformation <= MAX_VALUE) transformation += counter; // Если правый флаг поднят и значение "transformation" меньше "MAX_VALUE", то производим инкремент счётчика
if (Left_Turns == true && transformation >= MIN_VALUE) transformation -= counter; // Если левый флаг поднят и значение "transformation" больше "MIN_VALUE", то производим декремент счётчика
auto_val = constrain(auto_val, LEFT_CORNER, RIGHT_CORNER); // Ограничим диапазон для безопасности от "LEFT_CORNER" до "RIGHT_CORNER"
auto_val = map(transformation, MIN_VALUE, MAX_VALUE, LEFT_CORNER, RIGHT_CORNER); // Задаём диапазон скорости и поворота Servo (углы поворота от "LEFT_CORNER" до "RIGHT_CORNER" градусов)
rotation.write(auto_val); // Записываем положение в Servo
}
Да, нет, давайте уж полный код, вместе со схемой подключения. По куску кода разбираться - гороху наесться можно. Давайте всё полностью, а ещё лучше - модель в протеусе, которую можно тупо запустить и увидеть проблему.
Да, нет, давайте уж полный код, вместе со схемой подключения. По куску кода разбираться - гороху наесться можно. Давайте всё полностью, а ещё лучше - модель в протеусе, которую можно тупо запустить и увидеть проблему.
Другие части кода не взаимодействуют с Servo, всё, что связано с Servo в коде выложено уже сразу, что бы не путать с лишним кодом. Вырезанный код и полный работают одинаково.
Протеус не использовал, нет смысла, схема простая и всё на реальном железе создавал с нуля.
Схема:

Плата в Arduino IDE:"MiniCore"
Код по вкладкам (по порядку):
1)
2)
/*** БИБЛИОТЕКИ ***/ #include <TimerMs.h> // Многофункциональный программный таймер на системном таймере millis() для Arduino #include <SoftServo.h> // Библиотека для программного управления Servo (на базе millis/micros) #include <NecDecoder.h> // Лёгкая библиотека для декодирования ИК протокола NEC #include <FRAM.h> // Библиотека для работы с FRAM памятью (записываем положение Servo) #include <microWire.h> // Подключаем лёгкую библиотека со стандартным набором инструментов для работы с аппаратным I2C /*** ОБЪЕКТЫ ***/ SoftServo rotation; // Создаём Объект для Sertvo NecDecoder ir; // Создаём Объект для ИК приёмника FRAM fram(ADDRR_FRAM); // Задаём адрес i2c для FRAM памяти // (период, мс), (0 не запущен / 1 запущен), (режим: 0 период / 1 таймер) TimerMs mode1 (TIMER_MODE1, 0, 1); // Режим 1 на все 4 скорости (Timer1) TimerMs mode2 (TIMER_MODE2, 0, 1); // Режим 2 на все 4 скорости (Timer2) TimerMs mode3 (TIMER_MODE3, 0, 1); // Режим 3 на все 4 скорости (Timer3) TimerMs mode4 (TIMER_MODE4, 0, 1); // Режим 4 на все 4 скорости (Timer4) TimerMs mode5 (TIMER_MODE5, 0, 1); // Режим 5 только на пониженную скорость (Timer5) TimerMs mode6 (TIMER_MODE6, 0, 1); // Режим 6 только на пониженную скорость (Timer6) TimerMs blink_LOW (LED_BLINK_LOW, 0, 1); // Таймер для мигания "LED_GREAN" в LOW режимах /*** ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ***/ //Управление пинами МК const byte Relay_Array[4] = {RELAY1, RELAY2, RELAY3, RELAY4}; // Массив реле const byte Led_Array[3] = {LED_GREAN, LED_BLUE, LED_RED}; // Массив LED //Автоповороты Servo int servo_val = fram.ReadInt(PAGE_FRAM, SECTOR_FRAM); // Считываем в переменную "servo_val" значения с сектора "SECTOR_FRAM", страницы "PAGE_FRAM" int dir = 1; // Градус поворота для каждой итерации функции bool auto_RotatON = false; // Если "true", то включаем автоповороты Servo uint32_t tmr_auto = 0; // Последнее обновление времени (для автоповоротов Servo) //Ручные повороты Servo int transformation = 0; // Переменная для преобразования ручных поворотов через map() int counter = 1; // Увеличиваем перемещение на каждом шаге для ручных поворотов bool RotatON = false; // Если "true", то включаем повороты Servo(влево - вправо) bool Right_Turns = false; // Если "true", то поворачиваем вручную Servo вправо (при зажатии кнопки вправо) bool Left_Turns = false; // Если "true", то поворачиваем вручную Servo влево (при зажатии кнопки влево) uint32_t tmr_turn = 0; // Последнее обновление времени (для ручных поворотов Servo) //Для режима LOW (мигание "LED_GREAN") bool blink_ON = false; // Если "true", то включаем мигание LED в режиме LOW //Массив флагов для защиты от быстрого откл./вкл. (перещёлкивания) реле при повторном приёме ИК сигнала и в пределах одного режима //Первый элемент массива "нулевой" используется для флага задержки "DELAY_REL_OFF" между переключениями реле, остальные флаги для переключения смены режимов bool repeat[] = {0, 0, 0, 0, 0}; // Объявляем массив без явного задания размера3)
void setup() { //Назначаем все РЕЛЕ и LED как ВЫХОД for (byte r = 0; r < 4; r++) pinMode(Relay_Array[r], OUTPUT); for (byte l = 0; l < 3; l++) pinMode(Led_Array[l], OUTPUT); //Выключаем все РЕЛЕ for (byte r = 0; r < 4; r++) digitalWrite(Relay_Array[r], !RELAY_TYPE); // Инвертируем состояние заданное в "RELAY_TYPE" //Выключаем все LED for (byte l = 0; l < 3; l++) digitalWrite(Led_Array[l], LOW); //Получение ИК сигнала через прерывания attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN_IR), irIsr, FALLING); //Уставливаем в режим таймера (остановится после срабатывания) mode1.setTimerMode(); // 6 режимов таймеров для всех 4-х скоростей mode2.setTimerMode(); mode3.setTimerMode(); mode4.setTimerMode(); mode5.setTimerMode(); mode6.setTimerMode(); blink_LOW.setPeriodMode(); // Установить в режим периода (будет постоянно перезапускаться после срабатывания) //Настройки Servo //Защита от сильного дребезжания и зависания Servo с большим потреблением тока if (servo_val > RIGHT_CORNER || servo_val < LEFT_CORNER) servo_val = (RIGHT_CORNER - LEFT_CORNER) / 2; // Если считанный из FRAM угол выходит за пределы заданных, то переводим серво в центральное положение от заданных углов rotation.attach(SERVOMOTOR); // Вкл. Servo rotation.delayMode(); // переключить в режим задержки (по умолчанию) rotation.write(servo_val); // Записываем положение Servo из FRAM после включения питания fram.WriteInt(PAGE_FRAM, SECTOR_FRAM, servo_val); //Записываем в сектор "SECTOR_FRAM", "PAGE_FRAM" страницы значение "servo_val" }4)
void loop() { rotation.tick(); //Вызываем тикер для работы "SoftServo.h" // Ждём нажатия кнопки Вкл. автоповоротов или ручных поворотов с ИК пульта, если получили сигнал, то проверяем какой: if (auto_RotatON == true) auto_Rotation(); // Запускаем функцию вкл. автоповоротов Servo if (RotatON == true) manual_Turns(); // Иначе работает функция ручных поворотов Servo //Если флаги "blink_ON" и "blink_LOW.tick()" подняты, то переключаем состояние "LED_GREAN" на противоположное с периодичностью таймера "blink_LOW" if (blink_ON == true && blink_LOW.tick() == true) digitalWrite(LED_GREAN, !digitalRead(LED_GREAN)); ir_Decoder(); // Проверяем функцию "ir_Decoder()" на наличие приёма команд с ИК пульта mode_Timer(); // Проверяем функцию "mode_Timer()" на наличие работающих таймеров }5)
// Функция для обработки прерывания void irIsr() { ir.tick(); // Вызывать при ОТРИЦАТЕЛЬНОМ (FALLING) фронте на пине ИК приемника в прерывании //При удержании любой кнопки срабатывает прерывание и перехватываем пустой ИК сигнал, считаем его за код кнопки. При отпускании кнопки считаем, что код перестал приниматься tmr_turn = millis(); // Записываем текущее время (для ручных поворотов Servo) } //Если вызвать функцию "WriteRelLed(pin_Rel, pin_Led)"с аргументами, то переключимся на выбранное РЕЛЕ и LED //Функция упрощения Вкл./Выкл. РЕЛЕ и LED и уменьшения кода при многократных обращениях к пинам void WriteRelLed(byte pin_Rel, byte pin_Led) { // номер пина РЕЛЕ - "pin_Rel", номер пина LED - "pin_Led", которые будут Вкл. //Выключаем все РЕЛЕ digitalWrite(RELAY1, !RELAY_TYPE); // Инвертируем состояние заданное в "RELAY_TYPE" digitalWrite(RELAY2, !RELAY_TYPE); digitalWrite(RELAY3, !RELAY_TYPE); digitalWrite(RELAY4, !RELAY_TYPE); //Останавливаем все таймеры mode1.stop(); mode2.stop(); mode3.stop(); mode4.stop(); mode5.stop(); mode6.stop(); blink_LOW.stop(); // Останавливаем таймер для мигающего LED в режиме LOW blink_ON = false; // Опускаем флаг для мигающего LED в режиме LOW if (repeat[0] == 1) { // Если флаг "repeat[0]" поднят, то включаем задержку delay(DELAY_REL_OFF); // Ждём, пока контакты реле разъединятся после отключения repeat[0] = 0; // Опускаем флаг } //Вкл. нужное РЕЛЕ из массива (в массиве счёт начинается с нуля, поэтому дописываем -1 от pin_Rel) digitalWrite(Relay_Array[pin_Rel - 1], RELAY_TYPE); // Вкл. нужное реле при состоянии "RELAY_TYPE" //Выключаем все LED digitalWrite(LED_GREAN, LOW); digitalWrite(LED_BLUE, LOW); digitalWrite(LED_RED, LOW); //Вкл. нужный LED из массива (в массиве счёт начинается с нуля, поэтому дописываем -1 от pin_Led) digitalWrite(Led_Array[pin_Led - 1], HIGH); // Вкл. нужный LED } //Если вызвать функцию "WriteRelLed()" без аргументов, то выключатся все РЕЛЕ и LED void WriteRelLed() { // Выключаем ВСЁ //Выключаем все РЕЛЕ digitalWrite(RELAY1, !RELAY_TYPE); // Инвертируем состояние заданное в "RELAY_TYPE" digitalWrite(RELAY2, !RELAY_TYPE); digitalWrite(RELAY3, !RELAY_TYPE); digitalWrite(RELAY4, !RELAY_TYPE); //Выключаем все LED digitalWrite(LED_GREAN, LOW); digitalWrite(LED_BLUE, LOW); digitalWrite(LED_RED, LOW); //Останавливаем все таймеры mode1.stop(); mode2.stop(); mode3.stop(); mode4.stop(); mode5.stop(); mode6.stop(); blink_LOW.stop(); // Останавливаем таймер для мигающего LED в режиме LOW blink_ON = false; // Опускаем флаг для мигающего LED в режиме LOW //Блок защиты от быстрого откл./вкл. (перещёлкивания) реле при повторном приёме ИК сигнала и в пределах одного режима for (byte i = 0; i < sizeof(repeat); i++) { // Вычисляем размер массива repeat[i] = 0; // Присваиваем всему массиву ноль (false), тем самым делаем доступный любой режим для включения } } //Функция с поднятием одного заданного флага и опусканием всех остальных флагов (для защиты и одновременного включения двух релюшек) void flag_Array(byte flag_Read) { for (byte f = 0; f < sizeof(repeat); f++) { // Вычисляем размер массива и повторяем столько же раз, какой и размер массива for (byte i = 0; i < flag_Read; i++) { // Подставляем число полученное в функцию repeat[f] = 0; // Опускаем все флаги repeat[flag_Read] = 1; // И поднимаем нужный (заданный) флаг } } }6)
//Функция приёма данных с ИК пульта void ir_Decoder() { if (ir.available()) { // Если пакет успешно принят, то... switch (ir.readCommand()) { // Читаем команду case IR_OK: //Кнопка OK: Off (Выключить ВСЁ) WriteRelLed(); // Выключаем всё RotatON = false; // Опускаем флаг для ручных поворотов auto_RotatON = false; // Опускаем флаг для Автоповоротов break; case IR_UP: //Кнопка вверх: ↑ Авто - Вращения Вкл. RotatON = false; // Опускаем флаг для ручных поворотов auto_RotatON = true; // Поднимаем флаг для Вкл. Автоповоротов break; case IR_DOWN: //Кнопка вниз: ↓ Авто - Вращения Выкл. RotatON = false; // Опускаем флаг для ручных поворотов auto_RotatON = false; // Опускаем флаг для Автоповоротов break; case IR_LEFT: //Кнопка <: « Влево auto_RotatON = false; // Опускаем флаг для Автоповоротов RotatON = true; // Поднимаем флаг для ручных поворотов Right_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "« Влево" break; case IR_RIGHT: //Кнопка >: Вправо » auto_RotatON = false; // Опускаем флаг для Автоповоротов RotatON = true; // Поднимаем флаг для ручных поворотов Left_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "Вправо »" break; case IR_1: //Кнопка 1: 1 режим (On) (без таймера) if (repeat[1] == 0) repeat[0] = 1; // Если у элемента массива "repeat[1]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(1, 1); // Вкл. "RELAY1" и "LED_GREAN" без таймера flag_Array(1); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_2: //Кнопка 2: 2 режим (On) (без таймера) if (repeat[2] == 0) repeat[0] = 1; // Если у элемента массива "repeat[2]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(2, 2); // Вкл. "RELAY2" и "LED_BLUE" без таймера flag_Array(2); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_3: //Кнопка 3: 3 режим (On) (без таймера) if (repeat[3] == 0) repeat[0] = 1; // Если у элемента массива "repeat[3]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(3, 3); // Вкл. "RELAY3" и "LED_RED" без таймера flag_Array(3); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_4: //Кнопка 4: 1 режим (Timer1) if (repeat[1] == 0) repeat[0] = 1; // Если у элемента массива "repeat[1]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(1, 1); // Вкл. "RELAY1" и "LED_GREAN" mode1.start(); // Запускаем таймер для режима 1 (для всех 4-х скоростей) flag_Array(1); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_5: //Кнопка 5: 2 режим (Timer1) if (repeat[2] == 0) repeat[0] = 1; // Если у элемента массива "repeat[2]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(2, 2); // Вкл. "RELAY2" и "LED_BLUE" mode1.start(); // Запускаем таймер для режима 1 (для всех 4-х скоростей) flag_Array(2); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_6: //Кнопк 6: 3 режим (Timer1) if (repeat[3] == 0) repeat[0] = 1; // Если у элемента массива "repeat[3]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(3, 3); // Вкл. "RELAY3" и "LED_RED" mode1.start(); // Запускаем таймер для режима 1 (для всех 4-х скоростей) flag_Array(3); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_7: //Кнопка 7: 1 режим (Timer2) if (repeat[1] == 0) repeat[0] = 1; // Если у элемента массива "repeat[1]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(1, 1); // Вкл. "RELAY1" и "LED_GREAN" mode2.start(); // Запускаем таймер для режима 2 (для всех 4-х скоростей) flag_Array(1); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_8: //Кнопка 8: 2 режим (Timer2) if (repeat[2] == 0) repeat[0] = 1; // Если у элемента массива "repeat[2]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(2, 2); // Вкл. "RELAY2" и "LED_BLUE" mode2.start(); // Запускаем таймер для режима 2 (для всех 4-х скоростей) flag_Array(2); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_9: //Кнопка 9: 3 режим (Timer2) if (repeat[3] == 0) repeat[0] = 1; // Если у элемента массива "repeat[3]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(3, 3); // Вкл. "RELAY3" и "LED_RED" mode2.start(); // Запускаем таймер для режима 2 (для всех 4-х скоростей) flag_Array(3); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_10: //Кнопка +10: 1 режим (Timer3) if (repeat[1] == 0) repeat[0] = 1; // Если у элемента массива "repeat[1]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(1, 1); // Вкл. "RELAY1" и "LED_GREAN" mode3.start(); // Запускаем таймер для режима 3 (для всех 4-х скоростей) flag_Array(1); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_0: //Кнопка 0: 2 режим (Timer3) if (repeat[2] == 0) repeat[0] = 1; // Если у элемента массива "repeat[2]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(2, 2); // Вкл. "RELAY2" и "LED_BLUE" mode3.start(); // Запускаем таймер для режима 3 (для всех 4-х скоростей) flag_Array(2); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_T_SEARCH: //Кнопка T-SEARCH: 3 режим (Timer3) if (repeat[3] == 0) repeat[0] = 1; // Если у элемента массива "repeat[3]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(3, 3); // Вкл. "RELAY3" и "LED_RED" mode3.start(); // Запускаем таймер для режима 3 (для всех 4-х скоростей) flag_Array(3); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_STEP: if (repeat[1] == 0) repeat[0] = 1; // Если у элемента массива "repeat[1]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(1, 1); // Вкл. "RELAY1" и "LED_GREAN" mode4.start(); // Запускаем таймер для режима 4 (для всех 4-х скоростей) flag_Array(1); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_PLAY_PAUSE: //Кнопка PLAY/PAUSE: 2 режим (Timer4) if (repeat[2] == 0) repeat[0] = 1; // Если у элемента массива "repeat[2]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(2, 2); // Вкл. "RELAY2" и "LED_BLUE" mode4.start(); // Запускаем таймер для режима 4 (для всех 4-х скоростей) flag_Array(2); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_STOP: //Кнопка STOP: 3 режим (Timer4) if (repeat[3] == 0) repeat[0] = 1; // Если у элемента массива "repeat[3]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(3, 3); // Вкл. "RELAY3" и "LED_RED" mode4.start(); // Запускаем таймер для режима 4 (для всех 4-х скоростей) flag_Array(3); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_SUBTITLE: //Кнопка SUBTITLE: LOW (On) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_ANGLE: //Кнопка ANGLE: LOW (Timer1) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode1.start(); // Запускаем таймер для режима 1 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_AUDIO: //Кнопка AUDIO: LOW (Timer2) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode2.start(); // Запускаем таймер для режима 2 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_ZOOM: //Кнопка ZOOM: LOW (Timer3) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode3.start(); // Запускаем таймер для режима 3 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_RANDOM: //Кнопка RANDOM: LOW (Timer4) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode4.start(); // Запускаем таймер для режима 4 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_PROG: //Кнопка PROG: LOW (Timer5) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode5.start(); // Запускаем таймер для режима 5 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; case IR_KARAOKE: //Кнопка KARAOKE: LOW (Timer6) if (repeat[4] == 0) repeat[0] = 1; // Если у элемента массива "repeat[4]" флаг опущен, то поднимаем флаг первому элементу "repeat[0]" для задержки "DELAY_REL_OFF" WriteRelLed(4, 1); // Вкл. "RELAY4" и "LED_GREAN" mode6.start(); // Запускаем таймер для режима 6 (для LOW скорости) blink_LOW.start(); // Запускаем таймер для мигающего LED в режиме LOW blink_ON = true; // Поднимаем флаг для мигающего LED в режиме LOW flag_Array(4); // Поднимаем заданный флаг в скобках, а все остальные опускаем break; } } }7)
//Функция для Автоповоротов Servo void auto_Rotation() { if (millis() - tmr_auto >= AUTO_DELAY_TIME_SERVO) { // Если время больше или равно "AUTO_DELAY_TIME_SERVO", тогда... tmr_auto = millis(); // записываем время в "tmr_auto" servo_val += dir; // Прибавляем "servo_val" значение градуса "dir" if (servo_val >= RIGHT_CORNER || servo_val <= LEFT_CORNER) dir = -dir; // Разворачиваем в обратную сторону rotation.write(servo_val); // Записываем угол в Servo fram.WriteInt(PAGE_FRAM, SECTOR_FRAM, servo_val); //Записываем в сектор "SECTOR_FRAM", "PAGE_FRAM" страницы значение "servo_val" } } //Функция для ручных поворотов Servo (влево - вправо при удержании кнопки) void manual_Turns() { if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO) (Right_Turns = false), (Left_Turns = false); // Если вермя больше "TURNS_DELAY_TIME_SERVO", тогда опускам флаги if (Right_Turns == true && transformation <= MAX_VALUE) transformation += counter; // Если правый флаг поднят и значение "transformation" меньше "MAX_VALUE", то производим инкремент счётчика if (Left_Turns == true && transformation >= MIN_VALUE) transformation -= counter; // Если левый флаг поднят и значение "transformation" больше "MIN_VALUE", то производим декремент счётчика servo_val = constrain(servo_val, LEFT_CORNER, RIGHT_CORNER); // Ограничим диапазон для безопасности от "LEFT_CORNER" до "RIGHT_CORNER" servo_val = map(transformation, MIN_VALUE, MAX_VALUE, LEFT_CORNER, RIGHT_CORNER); // Задаём диапазон скорости и поворота Servo (углы поворота от "LEFT_CORNER" до "RIGHT_CORNER" градусов) rotation.write(servo_val); // Записываем положение в Servo fram.WriteInt(PAGE_FRAM, SECTOR_FRAM, servo_val); //Записываем в сектор "SECTOR_FRAM", "PAGE_FRAM" страницы значение "servo_val" }8)
//Функция отключения всех РЕЛЕ, LED и Автоповоротов по истечению работы таймера void mode_Timer() { if (mode1.tick() == true) { // Если таймер режима 1 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode1.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode1.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } if (mode2.tick() == true) { // Если таймер режима 2 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode2.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode2.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } if (mode3.tick() == true) { // Если таймер режима 3 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode3.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode3.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } if (mode4.tick() == true) { // Если таймер режима 4 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode4.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode4.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } if (mode5.tick() == true) { // Если таймер режима 5 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode5.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode5.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } if (mode6.tick() == true) { // Если таймер режима 6 запущен/перезапущен (пришла команда с ИК пульта), то... if (mode6.active() == false) { // Проверяем работает ли таймер (start/resume), если НЕ работает, то... WriteRelLed(); // Выключаем всё mode6.stop(); // Останавливаем таймер auto_RotatON = false; // Опускаем флаг для Автоповоротов } } }Есть у кого идея как решить проблему?
так и не понял откуда она возвращается если она стоит после остановок автоповоротов, а главное как она туда попала )))
так и не понял откуда она возвращается если она стоит после остановок автоповоротов, а главное как она туда попала )))
Включаю автоповороты, они крутятся себе, потом отключаю их, Servo остановился к примеру на угле в 50 градусов. Нужно что бы при нажатии кнопки ручных поворотов влево или вправо Servo продолжило движение в ту сторону, куда нажата кнопка с угла на котором остановилось Servo после автоповоротов.
И так же на ручных поворотах остановилась Servo на угле к примеру в 75 градусов и при включении Автоповоротов движение продолжилось с остановленного угла.
А то в моём случае после отключения автоповоротов Servo останавливается, нажимаю к примеру влево, и Servo резко возвращается в крайний угол и оттуда начинает поворачивать.
ну так запоминайте текущий угол каждой сервы в режиме авто - и потом в ручном режиме начинайте не с нуля, а с этого запомненного угла.
Вы бы подготовили специальный тестовый скетч с минимумом лишнего.... а то копаться в вашей куче разнородных файлов, выискивая что куда относится - это перебор
ну так запоминайте текущий угол каждой сервы в режиме авто - и потом в ручном режиме начинайте не с нуля, а с этого запомненного угла.
Вы бы подготовили специальный тестовый скетч с минимумом лишнего.... а то копаться в вашей куче разнородных файлов, выискивая что куда относится - это перебор
Пробовал, но как то не так что-то делаю и не получилось добиться результата.
Касаемо скетча, его с самого начала выложил, без всего лишнего, что бы не копаться.
Продублирую под спойлер:
//Servo (pin) #define SERVOMOTOR 9 // pin для подключения Servo //Прерывания (pin) #define INTERRUPT_PIN_IR 2 // Пин с прерыванием к которому подключён ИК приёмник //Настройки для ручных и автоповоротов Servo #define RIGHT_CORNER 130 // Задаём максимальный поворот на ПРАВЫЙ угол #define LEFT_CORNER 12 // Задаём максимальный поворот на ЛЕВЫЙ угол #define MAX_VALUE 20000 // Максимальное значение для задания скорости движения Servo при ручных поворотах #define MIN_VALUE 0 // Минимальное значение для задания скорости движения Servo при ручных поворотах #define AUTO_DELAY_TIME_SERVO 50 // Время повторений итераций(в миллисекундах) для автоповоротов. Чем больше время, тем медленее будут автоповороты #define TURNS_DELAY_TIME_SERVO 100 // Время (в миллисекундах) после истечения которого опускаем флаги (если не поступил новый сигнал) при ручных поворотах Servo #include <SoftServo.h> // Библиотека для программного управления Servo (на базе millis/micros) #include <NecDecoder.h> // Лёгкая библиотека для декодирования ИК протокола NEC //Коды кнопок пульта в HEX #define IR_UP 0x1 // Кнопка вверх: ↑ Авто - Вращения Вкл. #define IR_DOWN 0x81 // Кнопка вниз: ↓ Авто - Вращения Выкл. #define IR_LEFT 0x8A // Кнопка <: « Влево #define IR_RIGHT 0xB2 // Кнопка >: Вправо » SoftServo rotation; // Создаём Объект для Sertvo NecDecoder ir; // Создаём Объект для ИК приёмника //Автоповороты Servo int auto_val = 0; int dir = 1; // Градус поворота для каждой итерации функции bool auto_RotatON = false; // Если "true", то включаем автоповороты Servo uint32_t tmr_auto; // Последнее обновление времени (для автоповоротов Servo) //Ручные повороты Servo int transformation = 0; // Переменная для преобразования ручных поворотов через map() int counter = 1; // Увеличиваем перемещение на каждом шаге для ручных поворотов bool RotatON = false; // Если "true", то включаем повороты Servo(влево - вправо) bool Right_Turns = false; // Если "true", то поворачиваем вручную Servo вправо (при зажатии кнопки вправо) bool Left_Turns = false; // Если "true", то поворачиваем вручную Servo влево (при зажатии кнопки влево) uint32_t tmr_turn = 0; // Последнее обновление времени (для ручных поворотов Servo) void setup() { //Получение ИК сигнала через прерывания attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN_IR), irIsr, FALLING); if (auto_val > RIGHT_CORNER || auto_val < LEFT_CORNER) auto_val = (RIGHT_CORNER - LEFT_CORNER) / 2; // Если считанный из EEPROM угол выходит за пределы заданных, то переводим серво в центральное положение от заданных углов rotation.attach(SERVOMOTOR); // Вкл. Servo rotation.delayMode(); // переключить в режим задержки (по умолчанию) rotation.write(auto_val); // Записываем положение Servo из FRAM после включения питания } void loop() { rotation.tick(); //Вызываем тикер для работы "SoftServo.h" if (auto_RotatON == true) auto_Rotation(); // Запускаем функцию вкл. автоповоротов Servo if (RotatON == true) manual_Turns(); // Иначе работает функция ручных поворотов Servo ir_Decoder(); // Проверяем функцию "ir_Decoder()" на наличие приёма команд с ИК пульта } void irIsr() { ir.tick(); // Вызывать при ОТРИЦАТЕЛЬНОМ (FALLING) фронте на пине ИК приемника в прерывании //При удержании любой кнопки срабатывает прерывание и перехватываем пустой ИК сигнал, считаем его за код кнопки. При отпускании кнопки считаем, что код перестал приниматься tmr_turn = millis(); // Записываем текущее время (для ручных поворотов Servo) } void ir_Decoder() { //Получаем ИК коды if (ir.available()) { // Если пакет успешно принят, то... switch (ir.readCommand()) { // Читаем команду case IR_UP: //Кнопка вверх: ↑ Авто - Вращения Вкл. RotatON = false; // Опускаем флаг для ручных поворотов auto_RotatON = true; // Поднимаем флаг для Вкл. Автоповоротов break; case IR_DOWN: //Кнопка вниз: ↓ Авто - Вращения Выкл. RotatON = false; // Опускаем флаг для ручных поворотов auto_RotatON = false; // Опускаем флаг для Автоповоротов break; case IR_LEFT: //Кнопка <: « Влево auto_RotatON = false; // Опускаем флаг для Автоповоротов RotatON = true; // Поднимаем флаг для ручных поворотов Right_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "« Влево" break; case IR_RIGHT: //Кнопка >: Вправо » auto_RotatON = false; // Опускаем флаг для Автоповоротов RotatON = true; // Поднимаем флаг для ручных поворотов Left_Turns = true; // Поднимаем флаг при нажатии и удержании кнопки "Вправо »" break; } } } //Функция для Автоповоротов Servo void auto_Rotation() { if (millis() - tmr_auto >= AUTO_DELAY_TIME_SERVO) { // Если время больше или равно "AUTO_DELAY_TIME_SERVO", тогда... tmr_auto = millis(); // записываем время в "tmr_auto" auto_val += dir; // Прибавляем "auto_val" значение градуса "dir" if (auto_val >= RIGHT_CORNER || auto_val <= LEFT_CORNER) dir = -dir; // Разворачиваем в обратную сторону rotation.write(auto_val); // Записываем угол в Servo } } //Функция для ручных поворотов Servo (влево - вправо при удержании кнопки) void manual_Turns() { if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO) (Right_Turns = false), (Left_Turns = false); // Если вермя больше "TURNS_DELAY_TIME_SERVO", тогда опускам флаги if (Right_Turns == true && transformation <= MAX_VALUE) transformation += counter; // Если правый флаг поднят и значение "transformation" меньше "MAX_VALUE", то производим инкремент счётчика if (Left_Turns == true && transformation >= MIN_VALUE) transformation -= counter; // Если левый флаг поднят и значение "transformation" больше "MIN_VALUE", то производим декремент счётчика auto_val = constrain(auto_val, LEFT_CORNER, RIGHT_CORNER); // Ограничим диапазон для безопасности от "LEFT_CORNER" до "RIGHT_CORNER" auto_val = map(transformation, MIN_VALUE, MAX_VALUE, LEFT_CORNER, RIGHT_CORNER); // Задаём диапазон скорости и поворота Servo (углы поворота от "LEFT_CORNER" до "RIGHT_CORNER" градусов) rotation.write(auto_val); // Записываем положение в Servo }Тут в самом низу 2 функции
Пробовал, но как то не так что-то делаю и не получилось добиться результата.
покажите, как пробовали
Пробовал, но как то не так что-то делаю и не получилось добиться результата.
покажите, как пробовали
В глобальной переменной int transformation = tmr_auto;
А дальше затык с функцией map(), там сильно разнятся значения присвоенные "transformation" и "MAX_VALUE / MIN_VALUE".
сильно разнятся значения присвоенные "transformation" и "MAX_VALUE / MIN_VALUE".
а как так может быть. что пределы МАП в авто и в ручном режиме - разные? серва то одна и та же, пределы поворотов тоже одни и те же....
Добавка - я думаю именно в этом корень ваших проблем. Зачем вы задаете повороты в ручном и авто режиме в разных системах координат?
tmr_auto - в градусах, а transformation - в каких-то странных единицах от 0 до 2000
Что мешает в ручном режиме тоже использовать градусы. например?
Из-за того, что вы повороты задаете по разному, при передаче угла из одного режима в другой получается ерунда:
В глобальной переменной int transformation = tmr_auto;
так нельзя, у вас же две эти переменные в разных системах
А для чего вообще значение скорости переносить пропорционально в значение угла ?
сильно разнятся значения присвоенные "transformation" и "MAX_VALUE / MIN_VALUE".
а как так может быть. что пределы МАП в авто и в ручном режиме - разные? серва то одна и та же, пределы поворотов тоже одни и те же....
Добавка - я думаю именно в этом корень ваших проблем. Зачем вы задаете повороты в ручном и авто режиме в разных системах координат?
tmr_auto - в градусах, а transformation - в каких-то странных единицах от 0 до 2000
Что мешает в ручном режиме тоже использовать градусы. например?
Из-за того, что вы повороты задаете по разному, при передаче угла из одного режима в другой получается ерунда:
В глобальной переменной int transformation = tmr_auto;
так нельзя, у вас же две эти переменные в разных системах
Об этом упомянул вначале, что проблема скорее всего с преобразованием в map().
<< Что мешает в ручном режиме тоже использовать градусы. например?
Только ЗА, но не догоню как, точнее чем и на что заменить в преобразовании map(), подкиньте идею пожалуйста.
Какое нафиг преобразование ?
Зачем ?
Угол поворота , он и есть угол поворота.
Зачем его во что-то переводить ?
Что бы задать скорость поворотов. Если есть идея как уменьшить скорость поворотов, то напишите
Что бы задать скорость поворотов. Если есть идея как уменьшить скорость поворотов, то напишите
Так скорость поворотов , это время между инкрементом/декрементом угла.
Нафига ВРЕМЯ ПАУЗЫ между переключениями переводить в угол ???
Что бы задать скорость поворотов. Если есть идея как уменьшить скорость поворотов, то напишите
Не писал бы на форум если бы всё было чётко и работало как часики.
Поэтому и попросил помощи, что бы исправить косяки
Ещё раз попытаюсь объяснить.
Есть такой параметр как угол поворота.
Его мы передаём в функцию servo.write();
Этот угол мы меняем по определенному времени либо увеличиваем, либо уменьшаем.
Пауза между сменой угла будет задавать скорость поворота. Чем меньше пауза, тем больше скорость.
Так за каким хреном нужно переводить пропорционально значение ПАУЗЫ между сменой угла, к ЗНАЧЕНИЮ этого угла ?
За скорость поворотов отвечают строки 14 и 15. Они в коде вообще меняться не могут.
Вот примерно так функция ручного управления должна выглядеть:
void manual_Turns() { if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO){ tmr_turn=millis(); if (Right_Turns == true) auto_val+=counter; if (Left_Turns == true ) auto_val -= counter; Right_Turns=0; Left_Turnd=0; } auto_val = constrain(auto_val, LEFT_CORNER, RIGHT_CORNER); rotation.write(auto_val); }Не писал бы на форум если бы всё было чётко и работало как часики.
Поэтому и попросил помощи, что бы исправить косяки
вы вообще не догоняете. что ли?
Вот у вас есть процедура void auto_Rotation() в который вы поворачиваете серву, прибавляя или убавляя угол поворота В ГРАДКСАХ.
так что мешает точно так же поворачивать серву вручную, тоже меняя ГРАДУСЫ, а не какой-то левый параметр ?
Otto. в дополнение к тому что выше - я бы еще в код для ручных поворотов добавил таймер, чтобы он вызывался не каждый проход loop(), как сейчас, а через определенный интервал.
По-хорошему ручные повороты вполне можно делать через ту же функцию auto_Rotation() - просто вызываете ее по кнопке на определенный период времени, да и все. И тогда преобразование МАП вообще станет ненужным...
оффтоп: похоже что использование мап и констрэйн - почти всегда признак того, что автор не понимает смысла переменных в своем коде...
вместо переменно transformation не пробовал использовать одну и туже, что для автоматического режима, ведь логичней жеж
За скорость поворотов отвечают строки 14 и 15. Они в коде вообще меняться не могут.
Вот примерно так функция ручного управления должна выглядеть:
void manual_Turns() { if (millis() - tmr_turn > TURNS_DELAY_TIME_SERVO){ tmr_turn=millis(); if (Right_Turns == true) auto_val+=counter; if (Left_Turns == true ) auto_val -= counter; Right_Turns=0; Left_Turnd=0; } auto_val = constrain(auto_val, LEFT_CORNER, RIGHT_CORNER); rotation.write(auto_val); }Спасибо за пример, разобрав его, дошло, что можно было просто убрать дополнительные условия проверки и упростить код.
Вот только есть минус, что без функции map Servo стал более грубо поворачиваться, заметны рывки, особенно при декременте, подбором времени и значения счётчика пока не удалось решить эту проблему.
Вот только есть минус, что без функции map Servo стал более грубо поворачиваться, заметны рывки, особенно при декременте, подбором времени и значения счётчика пока не удалось решить эту проблему.
то что вы пишете - глупость. В функции МАП нет никакой магии, которую нельзя было бы получить просто подбором шага. Из чего можно сделать вывод. что вы опять ошиблись в логике кода.
Если хотите советов - показывайте новый код