Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"пилите Шура, пилите", точнее лучше тему "программа электронного дифференциала" пощупайте
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"Просто прибавить" это И-составляющая регулятора.
значит не прокатит, в авто при постоянной скорости движения ускорение одного и замедление другого колеса должно быть дифферинцировано, реализуется средствами осевого дифференциала, а у него ведущих осей - две, плюс межосевой не забываем )))
Прибавить убавить это уже П регулятор. Хотите Вы или нет. И регулятор нужен, что бы убрать маленькие ошибки, которые не видит П регулятор. ПИ регулятора во многих случаях достаточно. Д регулятор нужен если есть в наличии внешние воздействия большой амплитуды. Чтобы объект регулирования мог быстро отреагировать на изменившиеся обстоятельства. ПИД регулятор это собственно эти три регулятора в одном флаконе. Задав коэффициент ноль для любой из букв можно исключить букву из названия регулятора. Формула расчёта от этого не изменится.
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"Просто прибавить" это И-составляющая регулятора.
значит не прокатит, в авто при постоянной скорости движения ускорение одного и замедление другого колеса должно быть дифферинцировано, реализуется средствами осевого дифференциала, а у него ведущих осей - две, плюс межосевой не забываем )))
Значит говоришь о том, чего не понимаешь. Как и в следующем сообщении.
Короче говоря, изучил я его код-выложенный мной выше. Наворочено у него -по самое немогу. Да, всё круто и здорово. Но слишком круто. Нам не ракеты наводить :-).
У него 4 двигателя управляются- у меня 2. Ну и у него на freeRTOS. В целом,я ее понял. Но в деталях изучать ради одного случая-такое себе...
Убежден, что можно намного проще. В чем вижу минус, этого кода: робот становится "терминатором" которого не сбить ничем. Это плохо для моих целей (игра в хоккей-роботами). Почему: неинтересно. Все как влупили прямо -и хрен собъешь. Гораздо интересней, если робот в принципе едет прямо, но если его сбили или столкнули-едет прямо в другую сторону. Это гораздо интересней.
Сейчас еще раз снял показания с датчика-чтобы понимать его offset-ы. Попробую сам написать PID-регулятор, с учетом только поворота по Z (толчки и удары не учитываются-после удара робот поедет прямо "куда-то туда вбок". И это хорошо).
Согласен. Определение момента "толчка", "удара"-и что это именно был толчок/удар. И калибровка на их силу и т.д. и.т.п. Я вообще стал думать-не проще ли присобачить на каждое колесо по энкодеру-просто стабилизировать вращение колес и хрен с ним...
Из того, что есть под рукой- цифровые датчики Холла (много) и магнитики неодимовые. Штуки по 4 на колесо поставить. Да, это маленькое разрешение. Больше-лучше. Ну и ладно...будет вихляться туда-сюда, -но ехать... :-)))
Кстати, еще один вариант, который можно было бы применить (если не делать энкодер) - через каждые n миллисекунд - производить запись "начального положения". То есть не берем абсолют-который был в самом начале прямолинейного движения. А периодически пересчитываем этот абсолют. В этом случае, если произошел удар и существенное смещение-абсолютом будет считаться это новое положение. И робот не будет пытаться вернуться в "самое самое первое положение". А поедет прямо из текущего (в случайную сторону). Что и есть хорошо. Учитывая, что игровое поле маленькое- метра 3,5 в длину- то супер существенное накопление ошибки не должно происходить (при движении вперед, без воздействия ударов со стороны).
Мне кажется, Вы намечаете движение в направлении прямо противоположном требуемому: вместо того, чтобы запоминать и анализировать возмущающие воздействия, Вы предлагаете забывать первоначальные установки.
В общем, вроде синхронизировал колеса. Рассмотрел массу вариантов, - от магнитного энкодера на аналоговом датчике Холла, до оптического. Оптический оказался весьма даже неплох-фото приложил. Он выставлен точно таким образом-что "светит" инфракрасным лучом в гребенку колеса. Расстояние срабатывания настроено минимальное. Где то 5-6мм. Соответственно-есть гребенка-срабатывает. Провал между гребенками-нет. Датчик цифровой, всё "ну ащще четко и конкретно" :-))) Машинка-едет прямо.
То есть, функция срабатывает через раз(на каждое значение LOW). Машинке этого хватает для ровной езды. Пробовал ставить CHANGE-чтобы на любое изменение- энергопотребление выросло до небес и пошли глюки и отказы.
Но суть вопроса не в этом. В чем вопрос: как можно видеть выше, при возникновении прерывания-идет запуск функции sensor_impulse2
Вроде всё ок. Но есть момент, над которым ломаю голову: в составе этой функции sensor_impulse2 - есть Serial.println ("произошло прерывание, происходит всякое бла бла: " + blabla)
И вот этот вывод на экран -не срабатывает! Не могу понять, почему так...
Внутри прерывания не стоит выводить в сериал. Добавьте переменную - флаг и поднимайте его в прерывании. В основном цикле проверяйте - если поднят - опускайте и выводите сообщение.
Продолжаю пилить машинку- может кто дельного подскажет: на машинке сейчас запущен вебсервер, который выводит html-страничку, которая доступна по определенному ip адресу. Эта страничка служит пультом управления машинки.
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"пилите Шура, пилите", точнее лучше тему "программа электронного дифференциала" пощупайте
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"Просто прибавить" это И-составляющая регулятора.
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"Просто прибавить" это И-составляющая регулятора.
значит не прокатит, в авто при постоянной скорости движения ускорение одного и замедление другого колеса должно быть дифферинцировано, реализуется средствами осевого дифференциала, а у него ведущих осей - две, плюс межосевой не забываем )))
Прибавить убавить это уже П регулятор. Хотите Вы или нет. И регулятор нужен, что бы убрать маленькие ошибки, которые не видит П регулятор. ПИ регулятора во многих случаях достаточно. Д регулятор нужен если есть в наличии внешние воздействия большой амплитуды. Чтобы объект регулирования мог быстро отреагировать на изменившиеся обстоятельства. ПИД регулятор это собственно эти три регулятора в одном флаконе. Задав коэффициент ноль для любой из букв можно исключить букву из названия регулятора. Формула расчёта от этого не изменится.
Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))
Ищу ответ...
"Просто прибавить" это И-составляющая регулятора.
значит не прокатит, в авто при постоянной скорости движения ускорение одного и замедление другого колеса должно быть дифферинцировано, реализуется средствами осевого дифференциала, а у него ведущих осей - две, плюс межосевой не забываем )))
Значит говоришь о том, чего не понимаешь. Как и в следующем сообщении.
и что не так с дифференциалом?
Короче говоря, изучил я его код-выложенный мной выше. Наворочено у него -по самое немогу. Да, всё круто и здорово. Но слишком круто. Нам не ракеты наводить :-).
У него 4 двигателя управляются- у меня 2. Ну и у него на freeRTOS. В целом,я ее понял. Но в деталях изучать ради одного случая-такое себе...
Убежден, что можно намного проще. В чем вижу минус, этого кода: робот становится "терминатором" которого не сбить ничем. Это плохо для моих целей (игра в хоккей-роботами). Почему: неинтересно. Все как влупили прямо -и хрен собъешь. Гораздо интересней, если робот в принципе едет прямо, но если его сбили или столкнули-едет прямо в другую сторону. Это гораздо интересней.
Сейчас еще раз снял показания с датчика-чтобы понимать его offset-ы. Попробую сам написать PID-регулятор, с учетом только поворота по Z (толчки и удары не учитываются-после удара робот поедет прямо "куда-то туда вбок". И это хорошо).
А вот это сложнее, чем тупо всегда возвращаться на прямую. (если работать по IMU).
Согласен. Определение момента "толчка", "удара"-и что это именно был толчок/удар. И калибровка на их силу и т.д. и.т.п. Я вообще стал думать-не проще ли присобачить на каждое колесо по энкодеру-просто стабилизировать вращение колес и хрен с ним...
Из того, что есть под рукой- цифровые датчики Холла (много) и магнитики неодимовые. Штуки по 4 на колесо поставить. Да, это маленькое разрешение. Больше-лучше. Ну и ладно...будет вихляться туда-сюда, -но ехать... :-)))
Сделать просто и проверенно и как было посоветовано еще месяц назад? Ну ты безумец.
Хотел как проще ;-)
Все-таки прикрепить плату акселерометра проще-чем городить 2 энкодера.
Хотел как проще ;-)
Все-таки прикрепить плату акселерометра проще-чем городить 2 энкодера.
Кстати, еще один вариант, который можно было бы применить (если не делать энкодер) - через каждые n миллисекунд - производить запись "начального положения". То есть не берем абсолют-который был в самом начале прямолинейного движения. А периодически пересчитываем этот абсолют. В этом случае, если произошел удар и существенное смещение-абсолютом будет считаться это новое положение. И робот не будет пытаться вернуться в "самое самое первое положение". А поедет прямо из текущего (в случайную сторону). Что и есть хорошо. Учитывая, что игровое поле маленькое- метра 3,5 в длину- то супер существенное накопление ошибки не должно происходить (при движении вперед, без воздействия ударов со стороны).
Мне кажется, Вы намечаете движение в направлении прямо противоположном требуемому: вместо того, чтобы запоминать и анализировать возмущающие воздействия, Вы предлагаете забывать первоначальные установки.
В общем, вроде синхронизировал колеса. Рассмотрел массу вариантов, - от магнитного энкодера на аналоговом датчике Холла, до оптического. Оптический оказался весьма даже неплох-фото приложил. Он выставлен точно таким образом-что "светит" инфракрасным лучом в гребенку колеса. Расстояние срабатывания настроено минимальное. Где то 5-6мм. Соответственно-есть гребенка-срабатывает. Провал между гребенками-нет. Датчик цифровой, всё "ну ащще четко и конкретно" :-))) Машинка-едет прямо.
Одного не пойму что-то никак.
У меня к пинам датчиков подключены прерывания.
Выглядит так: attachInterrupt(SensorPin2, sensor_impulse2, LOW);
То есть, функция срабатывает через раз(на каждое значение LOW). Машинке этого хватает для ровной езды. Пробовал ставить CHANGE-чтобы на любое изменение- энергопотребление выросло до небес и пошли глюки и отказы.
Но суть вопроса не в этом. В чем вопрос: как можно видеть выше, при возникновении прерывания-идет запуск функции sensor_impulse2
Вроде всё ок. Но есть момент, над которым ломаю голову: в составе этой функции sensor_impulse2 - есть Serial.println ("произошло прерывание, происходит всякое бла бла: " + blabla)
И вот этот вывод на экран -не срабатывает! Не могу понять, почему так...
Внутри прерывания не стоит выводить в сериал. Добавьте переменную - флаг и поднимайте его в прерывании. В основном цикле проверяйте - если поднят - опускайте и выводите сообщение.
И вот этот вывод на экран -не срабатывает! Не могу понять, почему так...
потому что вывод в сериал сам использует прерывания поэтому внутри другого прерывания не работает
Хорошая информация!
Продолжаю пилить машинку- может кто дельного подскажет: на машинке сейчас запущен вебсервер, который выводит html-страничку, которая доступна по определенному ip адресу. Эта страничка служит пультом управления машинки.
Пилил по этому мануалу:
wikihandbk.com/ruwiki/index.php?title=ESP32:Примеры/Машинка-робот_с_дистанционным_WiFi-управлением
Вроде все ок. Но есть минус: нажал кнопку,-и машинка едет вперед пока не нажмешь "стоп". И со всеми кнопками то же самое.
То есть нет режима "нажал-одно происходит; отпустил-другое".
Пытаюсь переделывать. Но пока не до конца допираю как. Пока допер только, что:
а) событие "onclick" - надо заменить на 2 разных: onkeydown и onkeyup - судя по вики по html.
б) не отключать клиента вебсервера-пока не произошло событие onkeyup.
Чего не получается сделать: чтобы одной и той же кнопке назначить onkeyup и onkeydown.
Сам код этого места выглядит так:
// Показываем веб-страницу: client.println("<!DOCTYPE HTML><html>"); client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); client.println("<link rel=\"icon\" href=\"data:,\">"); // При помощи CSS задаем стиль кнопок. // Попробуйте поэкспериментировать // с атрибутами «background-color» и «font-size», // чтобы стилизовать кнопки согласно своим предпочтениям: client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}"); client.println(".button { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-color: #4CAF50;"); client.println("border: none; color: white; padding: 12px 28px; text-decoration: none; font-size: 26px; margin: 1px; cursor: pointer;}"); client.println(".button2 {background-color: #555555;}</style>"); client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script></head>"); // веб-страница: client.println("<p><button class=\"button\" onkeydown=\"moveForward()\">FORWARD</button></p>"); client.println("<p><button class=\"button\" onkeydup=\"stopRobot()\">FORWARD</button></p>"); client.println("<div style=\"clear: both;\"><p><button class=\"button\" onclick=\"moveLeft()\">LEFT </button>"); client.println("<button class=\"button button2\" onclick=\"stopRobot()\">STOP</button>"); client.println("<button class=\"button\" onclick=\"moveRight()\">RIGHT</button></p></div>"); client.println("<p><button class=\"button\" onclick=\"moveReverse()\">REVERSE</button></p>"); // client.println("<p>Motor Speed: <span id=\"motorSpeed\"></span></p>"); // client.println("<input type=\"range\" min=\"0\" max=\"100\" step=\"25\" id=\"motorSlider\" onchange=\"motorSpeed(this.value)\" value=\"" + valueString + "\"/>"); client.println("<script>$.ajaxSetup({timeout:1000});"); client.println("function moveForward() { $.get(\"/forward\"); {Connection: close};}"); client.println("function moveLeft() { $.get(\"/left\"); {Connection: close};}"); client.println("function stopRobot() {$.get(\"/stop\"); {Connection: close};}"); client.println("function moveRight() { $.get(\"/right\"); {Connection: close};}"); client.println("function moveReverse() { $.get(\"/reverse\"); {Connection: close};}</script>"); // client.println("var slider = document.getElementById(\"motorSlider\");"); // client.println("var motorP = document.getElementById(\"motorSpeed\"); motorP.innerHTML = slider.value;"); // client.println("slider.oninput = function() { slider.value = this.value; motorP.innerHTML = this.value; }"); // client.println("function motorSpeed(pos) { $.get(\"/?value=\" + pos + \"&\"); {Connection: close};}</script>"); // client.println("<script>$.ajaxSetup({timeout:1000});"); // client.println("function moveForward() { $.get(\"/forward\"); {Connection: close};}"); // client.println("function moveLeft() { $.get(\"/left\"); {Connection: close};}"); // client.println("function stopRobot() {$.get(\"/stop\"); {Connection: close};}"); // client.println("function moveRight() { $.get(\"/right\"); {Connection: close};}"); // client.println("function moveReverse() { $.get(\"/reverse\"); {Connection: close};}"); // client.println("var slider = document.getElementById(\"motorSlider\");"); // client.println("var motorP = document.getElementById(\"motorSpeed\"); motorP.innerHTML = slider.value;"); // client.println("slider.oninput = function() { slider.value = this.value; motorP.innerHTML = this.value; }"); // client.println("function motorSpeed(pos) { $.get(\"/?value=\" + pos + \"&\"); {Connection: close};}</script>"); client.println("</html>"); // Пример HTTP-запроса: «GET /?value=100& HTTP/1.1»; // Он задает коэффициент заполнения ШИМ на 100% (255): // if(header.indexOf("GET /?value=")>=0) { // pos1 = header.indexOf('='); // pos2 = header.indexOf('&'); // valueString = header.substring(pos1+1, pos2); // // Задаем скорость мотора: // if (valueString == "0") { // ledcWrite(pwmChannel, 0); // digitalWrite(motor1Pin1, LOW); // digitalWrite(motor1Pin2, LOW); // digitalWrite(motor2Pin1, LOW); // digitalWrite(motor2Pin2, LOW); // } // else { // dutyCycle = map(valueString.toInt(), 25, 100, 200, 255); // ledcWrite(pwmChannel, dutyCycle); // Serial.println(valueString); // } // } // HTTP-ответ заканчивается еще одной пустой строкой: client.println(); // Выходим из цикла while(): break; } else { // Если получили символ новой строки, // то очищаем переменную «currentLine»: currentLine = ""; } } else if (c != '\r') { // Если получили что-либо, // кроме символа возврата каретки... currentLine += c; // ...добавляем эти данные // в конец переменной «currentLine» } } } // Очищаем переменную «header»: header = ""; // Отключаем соединение: client.stop(); Serial.println("Client disconnected."); // "Клиент отключен." Serial.println(""); }Это делается вебсокетами.
Ок, покопаю в эту сторону.