Почему моя задержка становится неточной через одну минуту ? Это заставляет мой сервопривод вибрировать
У меня есть необычная установка для охлаждения моего пива при контролируемой температуре (вы можете найти подробности и фото здесь, если хотите). Входным сигналом моей системы является температура, выходным сигналом - положение сервопривода.
Короче говоря, длинная история
При запуске сервопривод работает достаточно стабильно, но каждый раз после 67 секунд работы сервопривод внезапно начинает вибрировать. У меня есть осциллограф, и я вижу, что после 67 секунд вместо постоянных 2,3 мс длительность импульсов колеблется в небольшом диапазоне, например, между 2,300 и 2,320 мс, и этого диапазона достаточно, чтобы стать проблемой.
Что происходит в возрасте 67 лет ?? Есть ли какой - то перелив ? Я очень озадачен, потому что в целом мой код для pulse очень прост.
У меня возникла проблема с этим кодом, ветвью bs18b20 моего репо. Импульс генерируется в строке 293 с пользовательским кодом.
Больше контекста
Я уже обращался за помощью прямо здесь с моей настройкой. Мы определили, что использование Servo.h наряду с протоколом 1Wire приводит к тому, что прерывания, используемые обеими библиотеками, мешают друг другу, поэтому сервопривод получает неверные значения и тоже вибрирует. В моем последнем комментарии в этой теме я сказал, что проблема была решена, но позже я обнаружил проблему нестабильности сервопривода через некоторое время, как показано выше.
Чтобы преодолеть это, я сменил тактику, заменил свой bs18b20 на lm35, которому не нужен 1Wire, и снова переключился на Servo.h. Это сработало очень хорошо... в моей лаборатории электроники. Но тогда (реальность отстой) Я обнаружил, когда фактически использовал свое устройство на кухне, что иногда температура становится очень неправильной, и я подозреваю, что влажность изменяет показания напряжения моего lm35. И именно поэтому я пытаюсь снова вернуться к своему предыдущему решению с водонепроницаемым bs18b20.
Во время написания этой статьи stackexchange предложила этот поток с очень многообещающим решением, я обязательно попробую это сделать. Тем не менее, ради этого мне все еще интересно узнать, что вызывает мою проблему выше, поэтому я все равно публикую это.
1 ответ
Не вдаваясь в детали вашего кода, похоже, что у вас возникли проблемы с прерываниями. Согласно вашему комментарию, этот простой код дает очень неравномерную длину импульса:
digitalWrite(SERVO_PIN, HIGH);
delayMicroseconds(servo_value*1000);
digitalWrite(SERVO_PIN, LOW);
Функция delayMicroseconds()
задерживает на запрошенное время, плюс
любое время, затраченное на прерывания. Таким образом, если задержка является непоследовательной во время
servo_value
не изменяется, это может быть только из-за прерываний.
Попытка понять точные симптомы, вероятно, будет довольно сложной, так как
пришлось бы копаться в источниках библиотек, которые вы используете,
и просматривать каждый ISR там. Тот факт, что версия, затягивающая с
micros()
начинает плохо себя вести только через некоторое время, вероятно, из-за
очень медленного “биения” между синхронизацией вашего сервопривода и синхронизацией
прерывания. Тот факт, что импульс иногда длится на 20 мкс
дольше, согласуется с тем, что он прерывался на 20 мкс,
что для ISR было бы довольно долго, но не безумно долго.
Вместо того, чтобы пытаться детально анализировать, как прерывания мешают вашему сервоприводу, я бы рекомендовал полностью обойти проблему и управлять сервоприводом с помощью ШИМ-сигнала, генерируемого аппаратно. Это дало бы очень постоянную длину импульса, полностью защищенную от прерывания прерываниями. Вы можете достичь разрешения 0,5 мкс с периодом 20 мс, установив таймер 1 на быструю ШИМ и синхронизируя его на частоте 2 МГц, например:
// Настройка таймера 1 для управления сервоприводом
// на выводе OC1A = PB1 = цифровой 9.
void setup_timer()
{
TCCR1A = 0; // отменить конфигурацию ядра Arduino
TCCR1B = 0; // то же самое
ICR1 = 40000 - 1; // период = 20 мс = 40000 тактов таймера
OCR1A = 3000 - 1; // длительность импульса = 1,5 мс = 3000 тактов таймера
TCCR1A = _BV(COM1A1) // неинвертирующий ШИМ на OC1A
| _BV(WGM11); // режим 14: быстрая ШИМ, TOP = ICR1
TCCR1B = _BV(WGM12) // то же самое
| _BV(WGM13) // то же самое
| _BV(CS11); // тактовая частота @ F_CPU/8 = 2 МГц
}
Затем вы можете изменить длительность импульса, просто записав в OCR1A
: запишите
на единицу меньше желаемой длительности импульса, в единицах измерения 0,5 мкс.
Скорее всего, вы правы, и ваше решение - это то, которое я принял, хотя мне нравится, что некоторые люди из nices сделали уродливую часть, я использовал это: https://learn.adafruit.com/neopixels-and-servos/the-ticoservo-library и это действует как заклинание. Он делает под капотом именно то, что вы предлагаете, статья отличная. Тем не менее, мне бы хотелось понять порог в 67 (на самом деле больше похоже на 66) секунд., @Guillaume Deshors
- Как заставить сервопривод вращаться на угол больше 180°
- Подключение Arduino к сервоприводу с внешним источником питания
- Мой сервопривод не работает плавно
- Бесполезная проводка коробки и код
- Почему сервопривод не перемещается по углам должным образом
- Микро сервопривод не работает с Arduino UNO
- поворот позиционного серводвигателя более чем на 180 градусов
- Почему loop() останавливается?
пожалуйста, добавьте код к вопросу, @jsotola
попробуйте поставить
timer_20 = now;
в начале блокаif
, @jsotolaдесятичные 67 000 000 микросекунд равны шестнадцатеричным 3FE56C0 ... это очень близко к шестнадцатеричному значению 4000000 ... это может быть некоторый ролловер, но это не имеет никакого смысла, потому что это 27-битное число, @jsotola
Есть ли у вас такая же проблема, если вы используете
delayMicroseconds ()
вместоwhile (micros () < time_micros)
цикл?, @Edgar BonetДа @jsotola micros() переполняется примерно через 70 минут, а millis(), я думаю, через 70 000 минут. Так что это не должно быть моей проблемой. Я попробую переместить аффектацию timer_20, вы правы, но я не понимаю, как это может помочь., @Guillaume Deshors
@edgar-bonet Я действительно пробовал это, и проблемы усугубились! Сервопривод работает нестабильно с самого начала., @Guillaume Deshors
@jsotola Я попробовал переместить строку в начале блока if, и она ведет себя точно так же., @Guillaume Deshors
На первый взгляд мне кажется очень подозрительным, что двигатель начинает вибрировать через 67 секунд, что очень близко к 2 ^ 16 = 65536 миллисекунд..., @Sim Son