Сделал машинку а-ля танк. Думаю синхронизировать колеса. Как?

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Всем доброго!

Вкратце в чем суть: собрал машинку а-ля танк (два ведущих колеса, радиус разворота отсутствует-может развернуться на месте на 360 градусов).

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

Как думаю с этим бороться:

Вариант А(геморройный): установка энкодеров /или датчиков холла-на каждое колесо. И усреднять скорость через ШИМ: подгонять отстающее колесо или тормозить бегущее вперед. Вариант хороший-но геморный. Много всего надо собрать и наворотить.

Вариант Б: установка некого датчика ускорения просто на раму машинки. И уже по показателям датчика -регулировать обороты двигунов. Скажем пришла команда "вперед". А машинку сносит на 10 градусов влево. Значит корректируем скорости двигателей так, чтобы она ехала прямо. На мой взгляд-самый недурной вариант. Так как требует минимальных трудов по созданию физической части.

Вот такие "мюсли"....

Критикуем, соглашаемся и т.д. Любые идеи- приветствуются! :-)

sadman41
Offline
Зарегистрирован: 19.10.2016

Как бы хорошо было, если бы вдруг от дома провести подземный ход или чрез пруд выстроить каменный мост, на котором бы были по обеим сторонам лавки, и чтобы в них сидели купцы и продавали разные мелкие товары, нужные для крестьян.

mu_ssina
Offline
Зарегистрирован: 30.08.2013

P.S. забыл добавить-машинка будет ездить по практически идеальной ровной поверхности. Поэтому ускорением по Z можно пренебречь и задача упрощается (если ставить датчик на раму).

А если поставить 2 датчика на раму-около каждого колеса -то и вообще хорошо: мне кажется эта система будет выдавать корректирующие сигналы с достаточно приемлемой точностью. Идеала не надо- не в космос летим :-). Достаточно "более-менее ехать вперед". Это всё :-)

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mu_ssina пишет:

Вариант Б: установка некого датчика ускорения просто на раму машинки. И уже по показателям датчика -регулировать обороты двигунов. Скажем пришла команда "вперед". А машинку сносит на 10 градусов влево. Значит корректируем скорости двигателей так, чтобы она ехала прямо. На мой взгляд-самый недурной вариант. Так как требует минимальных трудов по созданию физической части.

 

Тут не датчик ускорения, а гироскоп нужен. Хотя они сейчас часто с акселерометрами в одном флаконе идут.

Вот, например https://aliexpress.ru/item/32918386356.html

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

задача решается обычным триммированием аппаратуры )))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:
Как бы хорошо было, если бы вдруг от дома провести подземный ход или чрез пруд выстроить каменный мост, на котором бы были по обеим сторонам лавки, и чтобы в них сидели купцы и продавали разные мелкие товары, нужные для крестьян.

"А после государь, прознав о такой удивительной дружбе, обоих наградил бы и пожаловал в генералы"

mu_ssina
Offline
Зарегистрирован: 30.08.2013

... :0D

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Но смех смехом, а подруливание с помощью акселерометра, - кажется мне здравой идеей. Тем более, если "аппа" - обычная клава и управление с компа.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

mu_ssina пишет:

Но смех смехом, а подруливание с помощью акселерометра, - кажется мне здравой идеей. Тем более, если "аппа" - обычная клава и управление с компа.

 а какая разница какая у вас аппаратура, надо просто вывести 0 точку, это делается простым триммированием и изобретать велосипед там, где всё уже давно изобретено напрасная трата времени

вот тут для внучки делал

mu_ssina
Offline
Зарегистрирован: 30.08.2013

В общем боролся, боролся с триммированием. Да- "некие симптомы" можно убрать. Но саму болезнь победить не получается...Может руки кривые конечно-не исключаю. Максимум, что удалось добиться- что машинка едет сантиметров 40 прямо, потом ее сносить начинает. Некого "ультимативно прямого" движения, которое есть даже у покупных машинок на радиоуправлении за 200 рублей из "FIXPRICE" -не удается добиться.

В общем, сегодня прикупил вот такой чип акселерометра/гироскопа. Буду делать постоянное автоподруливание (если пришла команда ехать вперед). 

reticular
Offline
Зарегистрирован: 09.06.2016

имхо рыскание только на акселерометре не реализовать. нужен еще магнитометр

 

 

rkit
Offline
Зарегистрирован: 23.11.2016

Матчасть-то перед покупкой читал? А то опять "может руки" окажется.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mu_ssina пишет:

у покупных машинок на радиоуправлении за 200 рублей из "FIXPRICE"

У них нету никаких акселерометров и вообще никаких "хз-чего-метров". Может Вам лучше сначала купить парочку да посмотреть что там и как, чем огород-то городить?

mu_ssina
Offline
Зарегистрирован: 30.08.2013

именно , что покупал. Понятно, что у них другая система- ведущая задняя единая ось и рулевая передняя.

Я просто для примера их назвал.

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Задача несколько упрощается тем, что ехать машинке надо всего пару метров. В хоккей будут играть. То есть, даже если будет накопление ошибки- но более плавное, чем при триммировании-уже хорошо.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mu_ssina пишет:

В хоккей будут играть.

У меня играли. Площадка и ворота и сейчас сохранились. Весело было.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А вообще, если Вам интересны "умные машинки", посмотрите вот эту тему. Там реально крутая наука - пользы ребятёнкам будет немеряно!

mu_ssina
Offline
Зарегистрирован: 30.08.2013

ага, тоже хочу веселуху устроить. Можно было бы конечно машинку не танкового типа. А именно ведущая ось, рулящая ось. Но у нее управляемость снижена, присутствует радиус поворота. А у танковой системы- отличная управляемость, есть возможность развернуться на 360 градусов прямо на месте.

Удар будет наноситься и корпусом и клюшкой специальной. Машинка очень резкая во вращении (стоит преобразователь на 12V и движки от этого напряжения просто зверями становятся :-)

 

P.S. вот тут люди собирали на этом акселерометре. Буду сейчас изучать...

 

mu_ssina
Offline
Зарегистрирован: 30.08.2013

ок, сейчас гляну, спасибо!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

mu_ssina пишет:

В общем боролся, боролся с триммированием.

у всех получается простым триммированием, кривую регулировки подстройте ежели что

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Кстати, может кто подскажет-сейчас копаю эту тему-т.к. не сталкивался:

Использую в esp32 8-битное разрешение ШИМ и, соответственно, от 0 до 255 уровней ШИМ - для регулировки скоростей двигателей.

Опытным путем было выяснено-что шаг в 1 единицу - слишком большой при триммировании. Надо мельче-т.к. выровнять почти удалось, но грубо.

То есть, на одном движке скорость у меня стоит скажем 72 (из 255 возможных), на другом - 73 (из 255 возможных).

Уже почти хорошо-но грубовато.

 

Вот и думаю-esp32 поддерживает 16-битное разрешение (у меня сейчас стоит 8-бит). 

Правильно ли понимаю, что если выставить 16-бит, то мне станут доступны 510 уровней корректировки сигнала? 

Короче говоря, копаю пока эту тему- как сделать более плавную регулировку ШИМ-не такую скачкоообразную...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

mu_ssina пишет:

Кстати, может кто подскажет-сейчас копаю эту тему-т.к. не сталкивался:

Использую в esp32 8-битное разрешение ШИМ и, соответственно, от 0 до 255 уровней ШИМ - для регулировки скоростей двигателей.

Опытным путем было выяснено-что шаг в 1 единицу - слишком большой при триммировании. Надо мельче-т.к. выровнять почти удалось, но грубо.

То есть, на одном движке скорость у меня стоит скажем 72 (из 255 возможных), на другом - 73 (из 255 возможных).

Уже почти хорошо-но грубовато.

 

Вот и думаю-esp32 поддерживает 16-битное разрешение (у меня сейчас стоит 8-бит). 

Правильно ли понимаю, что если выставить 16-бит, то мне станут доступны 510 уровней корректировки сигнала? 

Короче говоря, копаю пока эту тему- как сделать более плавную регулировку ШИМ-не такую скачкоообразную...

нет, станут доступны 65536 уровней )))

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

mu_ssina пишет:

Правильно ли понимаю, что если выставить 16-бит, то мне станут доступны 510 уровней корректировки сигнала? 

Грубо говоря, каждый бит разрешения удваивает количество уровней

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Ого! Спасибо!

И вот еще что: есть ли там какое то ограничение по частоте?

Скажем у меня сейчас частота стоит 30 000 при 8-битах. 

Могу ли я оставить частоту такой же(чтобы писка для уха было не слышно) -или придется понижать/повышать - при 16 битах?

Вопрос немного некорректный- ограничения по частоте есть-я знаю :-)

 

P.S. вопрос вроде снимается- вычитал такое:

"Очень просто настроить сигнал ШИМ на любой желаемой частоте с любым желаемым разрешением при условии, что вы не превысите максимальную «пропускную способность»: частота, умноженная на разрешение, должна быть меньше половины тактовой частоты устройство.

Полное объяснение по отношению к ESP-IDF составляет доступно здесь".

 

mu_ssina
Offline
Зарегистрирован: 30.08.2013

В общем вот как обстоят дела после всех тестов: да, с помощью расширенного диапазона ШИМ - удалось многое сгладить, но в силу разных причин(несбалансированность тележки, неровно стоят колеса, все-таки некоторое различие в скоростях двигателей)- кардинально улучшить прямолинейное движение не получается.

Поставил сейчас этот чип MPU 6050 и пытаюсь рулить акселерометром (пару дней). Пока получается так себе :-D. Ибо не умею. Накопал кучу кода для самобалансирующихся штук а-ля гироскутер. Но это не совсем то.

Может для моего случая (когда по сути надо всего то 1 ось считывать, обработать ошибки датчика и ехать прямо, я так думаю :-)))  - может кто подскажет дельное, или кто-то может делал такое?

Помурыжусь, потрачу кучу времени-я конечно найду, разберусь и сделаю...Но охота побыстрее :-))))

reticular
Offline
Зарегистрирован: 09.06.2016

тут поможет компас

 

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Нее, компас -это слишком ультимативно и круто :-). Почему: машинки будут сталкиваться друг с другом и менять траекторию движения друг друга. И это нормально. Гораздо хуже будет, если после столкновения -все опять поехали по своим старым траекториям. Это уже какие то роботы несбиваемые. Терминаторы :-))))

Не надо так... :-)

 

 

gena321
Offline
Зарегистрирован: 19.01.2019
Вот генератор на два канала с регулировкой ширины импульса на первом канале PB6 с помощью кнопок.
Заменить кнопки на радиоуправляемые.
 
HardwareTimer pwmtimer4(4);
#include <LiquidCrystal.h>
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
int i;
void setup()
{
    pinMode(PB12, INPUT_PULLDOWN);
  pinMode(PB14, INPUT_PULLDOWN);
  lcd.begin(16, 2);
  pinMode(PB6, PWM);//ch1
  pinMode(PB7, PWM);//ch2
  pwmtimer4.pause();
  pwmtimer4.setPrescaleFactor(1);
  pwmtimer4.setOverflow(3600);
  //pwmtimer4.setCompare(TIMER_CH1, 1800 +i);
  pwmtimer4.setCompare(TIMER_CH2, 1800);
  pwmtimer4.refresh();
  pwmtimer4.resume();
}
 
void loop() {
pwmtimer4.setCompare(TIMER_CH1, 1800 +i);
 
 if (digitalRead(PB12) == HIGH)
  {
    if (i < 6000)
      // if (i < 25)
    {
      i++;
     
      delay(50);
    }
  }
  if (digitalRead(PB14) == HIGH)
  {
    if (i > 0)
    {
      i--;
     
      delay(50);
    }
  }
  lcd.setCursor(0, 1);
  lcd.print(i);
  }

 

 
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

mu_ssina пишет:

...кардинально улучшить прямолинейное движение не получается.

Может для моего случая (когда по сути надо всего то 1 ось считывать...

Может, в том и проблема, что Вы обрабатываете всего одну ось?

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Да не...все правильно делаю. Только малость не то. Вчера нашел мануал одного чела-решал такую же задачу. Он пишет что решил так: вместо акселерометра-стал читать данные гироскопа. А конкретно ось Z. И этого достаточно, чтобы машинка ехала прямо. Глянул его видео-да все работает вроде...Сегодня буду так же пробовать.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

mu_ssina пишет:

Да не...все правильно делаю. Только малость не то. Вчера нашел мануал одного чела-решал такую же задачу. Он пишет что решил так: вместо акселерометра-стал читать данные гироскопа. А конкретно ось Z. И этого достаточно, чтобы машинка ехала прямо. Глянул его видео-да все работает вроде...Сегодня буду так же пробовать.

ну не знаю, у Онкеля ездят прямо, у меня прямо, у Архата аналогично, может машинки надо допилить напильником

mu_ssina
Offline
Зарегистрирован: 30.08.2013

А вы как сделали? Только триммированием? Или все-таки через акселерометр/гироскоп?

Расскажу как я пробовал через триммирование:

1 этап: поставил 8-бит (и соответственно 255 уровней).

Скорость выставил 70 уровней (чтобы не слишком быстро летала от 12 вольт).

Выяснилось, что на одном двигуне- 70, а на другом надо 62.

И тогда "почти получилось".  Но все равно-40-50 см проезжает и сносит вбок.

 

2 этап: поставил 10 бит (и соответственно 765 уровней).

Начал настраивать...Плюнул, все проклял :-)))))

И понял, что проще разобраться в гироскопе-чем вручную настроить и ловить эти мизеры на 10 машинках...

 

P.S. машинки особо "допиливать" некуда- они полностью 3d печатные. Там отклонения мизер...

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

mu_ssina пишет:

2 этап: поставил 10 бит (и соответственно 765 уровней).


10 бит - это 1024 уровня (0-1023) . Определяется просто - количество уровней = 2^n, где n - разрешение. В вашем случае 2^10=1024

mu_ssina
Offline
Зарегистрирован: 30.08.2013

ок, ошибся, сорри. 

Но я не про то хотел сказать. А про то, что при уменьшении шага настройки- задолбаешься настраивать вручную. Тем более 10 машин. Проще гироскоп понять и настроить ...

gena321
Offline
Зарегистрирован: 19.01.2019

mu_ssina пишет:

Выяснилось, что на одном двигуне- 70, а на другом надо 62.

И тогда "почти получилось".  Но все равно-40-50 см проезжает и сносит вбок.

тогда надо подстроить 60, для этого можнo использовать длинные провода для кнопок или радиоуправление. 
Надо настраивать когдо машина двигается.
LCD показывает величину подстройки.
 
gena321
Offline
Зарегистрирован: 19.01.2019
В моём генераторе 3600 уровней, это можно изменить
строка 13, поставить 10 в место 1, строка16 и 22 заменить 1800 на 180, тогда будет 360 уровней. 
ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

gena321 пишет:

mu_ssina пишет:

Выяснилось, что на одном двигуне- 70, а на другом надо 62.

И тогда "почти получилось".  Но все равно-40-50 см проезжает и сносит вбок.

тогда надо подстроить 60, для этого можнo использовать длинные провода для кнопок или радиоуправление. 
Надо настраивать когдо машина двигается.
LCD показывает величину подстройки.
 

думаешь не в движении триммировал? Оригинально

ЛЮБУЮ радиоуправляемую модель первым делом учат ходить, если требуется сильно большое триммирование подстраивают тяги, тяг у вам нет, значит обязана настраиваться, если разбаланс зависит от величины отклонения руля, подстраивают кривые управления, как то так и, каждую индивидуально

но мы так и не увидели кода, там может в коде косяки

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Ок, кидаю код.

Это код, без внесенной поправки на разный ход двигателей.

"Нулёвый" так сказать, с разрешением 8 бит(пока что). 

Версию кода с гироскопом пока не даю-т.к. работаю над ней. Давать нечего -все в разбросанных кусках:-)

Кстати, может по коду кто подскажет такую умную вещь: сейчас код запускает сервер на ESP32, на которой становится доступен интерфейс управления из браузера (по IP подключаешься к esp32 - и "вперде!" :-). 

В чем вопрос: кнопки реагируют только на нажатие. Нажатие/отпускание кнопки-не реагируют. Если бы прикрутить отпускание кнопки-было бы зело удобно :-)

 

/*********
  Руи Сантос
  Более подробно о проекте на: http://randomnerdtutorials.com  
*********/

// загружаем библиотеку для WiFi:
#include <WiFi.h>

// вставляем ниже SSID и пароль для своей WiFi-сети:
const char* ssid     = "Сюда SSID";  
const char* password = "сюда пароль";

// создаем объект сервера и задаем ему порт «80»:
WiFiServer server(80);

// переменная для хранения HTTP-запроса:
String header;

// мотор 1:
int motor1Pin1 = 18; 
int motor1Pin2 = 19; 
//int enable1Pin = 14; 

// мотор 2:
int motor2Pin1 = 16; 
int motor2Pin2 = 17; 
//int enable2Pin = 32;

// переменные для свойств широтно-импульсной модуляции (ШИМ) 1-двигателя:
const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 0;

// переменные для свойств широтно-импульсной модуляции (ШИМ) 2-двигателя:
const int freq2 = 30000;
const int pwmChannel2 = 1;
const int resolution2 = 8;
int dutyCycle2 = 0;


// переменные для расшифровки HTTP-запроса GET:
String valueString = String(5);
int pos1 = 0;
int pos2 = 0;


//Куда подключен датчик Холла:
int hallPin = 4;


void setup() {
  Serial.begin(115200);
  
  // переключаем контакты моторов в режим «OUTPUT»:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);


// подключаем контакт цифрового датчика Холла к пину, в режим «INPUT»:
pinMode (hallPin, INPUT);


  // задаем настройки ШИМ-канала каждого из 2 двигателей:
 
  ledcSetup(pwmChannel, freq, resolution); // первый двигатель
  ledcSetup(pwmChannel2, freq2, resolution2); // второй двигатель
  
  // подключаем ШИМ-канал, к контактам для управления скоростью вращения каждого из 2 моторов:

    ledcAttachPin(motor1Pin1, pwmChannel); // первый двигатель
    ledcAttachPin(motor2Pin1, pwmChannel2); // второй двигатель
 
  // подаем на контакты ШИМ-сигнал с коэффициентом заполнения «0»:
  ledcWrite(pwmChannel, dutyCycle);
  ledcWrite(pwmChannel2, dutyCycle2);
  
  // подключаемся к WiFi-сети при помощи заданных выше SSID и пароля:
  Serial.print("Connecting to ");  //  "Подключаемся к "
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // печатаем в мониторе порта
  // локальный IP-адрес и запускаем веб-сервер:
  Serial.println("");
  Serial.println("WiFi connected.");  //  "Подключились к WiFi-сети."
  Serial.println("IP address: ");  //  "IP-адрес: "
  Serial.println(WiFi.localIP());
  server.begin();


  
}

void loop(){
  WiFiClient client = server.available();  // Запускаем прослушку 
                                           // входящих клиентов.

  if (client) {                            // Если подключился 
                                           // новый клиент,
    Serial.println("New Client.");         // печатаем в монитор порта  
                                           // сообщение об этом.
    String currentLine = "";               // Создаем строку
                                           // для хранения данных,
                                           // пришедших от клиента.
    while (client.connected()) {           // Запускаем цикл while(), 
                                           // который будет работать,
                                           // пока клиент подключен.
      if (client.available()) {            // Если у клиента
                                           // есть байты, которые
                                           // можно прочесть,
        char c = client.read();            // считываем байт 
        Serial.write(c);                   // и печатаем его 
                                           // в мониторе порта.
        header += c;
        if (c == '\n') {                   // Если полученный байт – 
                                           // это символ новой строки.
          // Если мы получили два символа новой строки подряд,
          // то это значит, что текущая строка пуста.
          // Это конец HTTP-запроса клиента, поэтому отправляем ответ:
          if (currentLine.length() == 0) {
            // HTTP-заголовки всегда начинаются с кода ответа
            // (например, с «HTTP/1.1 200 OK»),
            // а также с информации о типе контента,
            // чтобы клиент знал, что получает.
            // После этого пишем пустую строчку:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
                       //  "Соединение: отключено"
            client.println();
            
            // Этот код отвечает за управление контактами моторов
            // согласно тому, какие нажаты кнопки на веб-странице:
           
            if (header.indexOf("GET /forward") >= 0) {
              
              Serial.println("Forward");  //  "Вперед"
              
              ledcWrite(pwmChannel, 0); //0 - максимум оборотов
              ledcWrite(pwmChannel2, 0); //0 - максимум оборотов
              digitalWrite(motor1Pin1, LOW);
              digitalWrite(motor1Pin2, HIGH); 
              digitalWrite(motor2Pin1, LOW);
              digitalWrite(motor2Pin2, HIGH);
              
              
            }  else if (header.indexOf("GET /left") >= 0) {
              
              Serial.println("Left");  //  "Влево"
               
                ledcWrite(pwmChannel, 255);
                ledcWrite(pwmChannel2, 0);                
                digitalWrite(motor1Pin1, HIGH); 
                digitalWrite(motor1Pin2, LOW); 
                digitalWrite(motor2Pin1, LOW);
                digitalWrite(motor2Pin2, HIGH);
               
        
           
            }  else if (header.indexOf("GET /stop") >= 0) {
            
              Serial.println("Stop");  //  "Стоп"
              
              ledcWrite(pwmChannel, 0);
              ledcWrite(pwmChannel2, 0);
              digitalWrite(motor1Pin1, LOW); 
              digitalWrite(motor1Pin2, LOW); 
              digitalWrite(motor2Pin1, LOW);
              digitalWrite(motor2Pin2, LOW);             
           
           
            } else if (header.indexOf("GET /right") >= 0) {
             
              Serial.println("Right");  //  "Вправо"
             
              ledcWrite(pwmChannel, 0);
              ledcWrite(pwmChannel2, 255);
              digitalWrite(motor1Pin1, LOW); 
              digitalWrite(motor1Pin2, HIGH); 
              digitalWrite(motor2Pin1, HIGH);
              digitalWrite(motor2Pin2, LOW);    
            
           
            } else if (header.indexOf("GET /reverse") >= 0) {
              
              Serial.println("Reverse");  //  "Назад"
             
              ledcWrite(pwmChannel, 255); //255 - максимум оборотов
              ledcWrite(pwmChannel2, 255); //255 - максимум оборотов
              digitalWrite(motor1Pin1, HIGH);
              digitalWrite(motor1Pin2, LOW); 
              digitalWrite(motor2Pin1, HIGH);
              digitalWrite(motor2Pin2, LOW);          
            }
            // Показываем веб-страницу:
            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\" onclick=\"moveForward()\">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("");
  }
}

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

mu_ssina пишет:

Да не...все правильно делаю. Только малость не то. Вчера нашел мануал одного чела-решал такую же задачу. Он пишет что решил так: вместо акселерометра-стал читать данные гироскопа. А конкретно ось Z. И этого достаточно, чтобы машинка ехала прямо. Глянул его видео-да все работает вроде...Сегодня буду так же пробовать.

 

Я еще 2 недели назад здесь писал, что гироскоп надо использовать, а не акселерометр. Акселерометр фиксирует ускорение вдоль оси, а гироскоп вращение вокруг оси. А если машинка отклоняется от прямой, то именно вращение и происходит. И как раз с гироскопом одной оси достаточно будет.

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Вчера вот такой код нашел любопытный-с фильтром Маджвика. Надо попробовать...

 

mu_ssina
Offline
Зарегистрирован: 30.08.2013

asam пишет:

mu_ssina пишет:

Да не...все правильно делаю. Только малость не то. Вчера нашел мануал одного чела-решал такую же задачу. Он пишет что решил так: вместо акселерометра-стал читать данные гироскопа. А конкретно ось Z. И этого достаточно, чтобы машинка ехала прямо. Глянул его видео-да все работает вроде...Сегодня буду так же пробовать.

 

Я еще 2 недели назад здесь писал, что гироскоп надо использовать, а не акселерометр. Акселерометр фиксирует ускорение вдоль оси, а гироскоп вращение вокруг оси. А если машинка отклоняется от прямой, то именно вращение и происходит. И как раз с гироскопом одной оси достаточно будет.

 

 

ага, было такое...:-)

Я как раз аксель+гироскоп взял потом. Вот такой. Попроще конечно-но сойдет. Нам не "боинги" сажать :-)

 

Izvekoff
Offline
Зарегистрирован: 02.03.2020

и где там триммирование?
Есть же стандарты для девайсов радиоуправления PWM, PPM, SBUS, IBUS
Тайминги 1000 - 1500 - 2000 надо к ним придти и вокруг них плясать
А так получилась уникальная не настраиваемая хрень

 

gena321
Offline
Зарегистрирован: 19.01.2019
Tриммирование не поможет, проверил со стробоскопом. 
Синхронизация срывается после одной секунды, нужен автобаланс. 
Если разница оборотов равна 1 оборот в секунду это разница в дороге гдето 5 см ........
 
 
gena321
Offline
Зарегистрирован: 19.01.2019

mu_ssina пишет:

А если поставить 2 датчика на раму-около каждого колеса -то и вообще хорошо: мне кажется эта система будет выдавать корректирующие сигналы с достаточно приемлемой точностью. Идеала не надо- не в космос летим :-). Достаточно "более-менее ехать вперед". Это всё :-)

Вот такой датчик, где то 20 импульсов на один оборот + простая программа автобаланса. 

https://cdn.usdigital.com/assets/images/posts/optical-encoder-tech.png

mu_ssina
Offline
Зарегистрирован: 30.08.2013

да, я изначально так примерно и думал. Если не получится с гироскопом( а это вряд ли, как я понимаю) - то можно будет пробовать такое...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

У ЕвгенийП точно есть код для тележки, внуки рассекали, и там всё прямо ехало, спросить как он решил проблему прямохода

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

спросить как он решил проблему прямохода

Там были BLDC драйверы с обратной связью (тахоимпульсы валились по хрен-помнит-сколько на оборот). Считал время между импульсами тахометров и подравнивал обороты двигателей в зависимости ещё от положения рулевого джойстика. При этом меня интересовали именно обороты двигателей, а не прямизна траектории. Например, если давление в шинах на одной стороне оказалось бы не такое, как на другой - машинка вполне могла и заворачивать, или из-за неровностей дороги - подруливание уже на водителе было.

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Пару дней назад накопал весьма ядреный труд (автор издает аж книги) - по автовыравниванию машинки. Там выложены полные листинги. Открываешь их и....крыша уезжает :-))))) Как минимум из-за того, что все работает из-под freeRTOS (встраиваемая операционка под esp32).

Сижу вот изучаю...А вот результат его трудов(один из): https://www.youtube.com/watch?v=XFPTE3VfiJ4

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

mu_ssina пишет:

Пару дней назад накопал весьма ядреный труд (автор издает аж книги) - по автовыравниванию машинки. Там выложены полные листинги. Открываешь их и....крыша уезжает :-))))) Как минимум из-за того, что все работает из-под freeRTOS (встраиваемая операционка под esp32).

Сижу вот изучаю...А вот результат его трудов(один из): https://www.youtube.com/watch?v=XFPTE3VfiJ4

посмотрел, есть ПИД регулятор, значит есть УНИТАЗИНГ, на видео мы его и видим )))
У вас машинка ручного управления, зачем плодить сущности?

rkit
Offline
Зарегистрирован: 23.11.2016

ua6em пишет:

mu_ssina пишет:

Пару дней назад накопал весьма ядреный труд (автор издает аж книги) - по автовыравниванию машинки. Там выложены полные листинги. Открываешь их и....крыша уезжает :-))))) Как минимум из-за того, что все работает из-под freeRTOS (встраиваемая операционка под esp32).

Сижу вот изучаю...А вот результат его трудов(один из): https://www.youtube.com/watch?v=XFPTE3VfiJ4

посмотрел, есть ПИД регулятор, значит есть УНИТАЗИНГ, на видео мы его и видим )))
У вас машинка ручного управления, зачем плодить сущности?

Без ПИ-регулятора или аналога ровное движение в этой ситуации сделать не получится

mu_ssina
Offline
Зарегистрирован: 30.08.2013

Кстати, сейчас гуглю теорию по ПИД-регуляторам. Давно хотел их понять-а тут как раз повод. Пока что на данный момент, мой ламерский вопрос звучит так: "зачем он вообще нужен, не проще ли просто прибавить/убавить скорость двигателя и всё тут" :-)))

Ищу ответ...