Управление двумя двигателями по радиомодулю
- Войдите на сайт для отправки комментариев
ЖЕЛЕЗО:
- Ардуино НАНО 2 шт.
- Радиомодуль NRF24L01 2 шт. (с адаптером питания 3.3В)
- Драйвер двигателя L298N (мини) 1 шт.
- Аналоговый джойстик 2 шт.
- Коллекторный двигатель 2 шт.
Всё соединяется без проблем.
ТЗ
Нужно два скетча TX/RX. Модель автомобиля с воздушными винтами.
АЛГОРИТМ
1. Оба джойстика в нейтральном положении - двигатели не работают.
2. При отклонении джойстика-1 от среднего положения вперед скорость обоих двигателей плавно нарастает (FORWARD).
3. При отклонении джойстика-1 от среднего положения назад скорость обоих двигателей плавно растет обратно (BACKWARD).
4. При смещении джойстика-2 осуществляется поворот: отклонение джойстика-2 от нейтрального меняет соотношение скоростей обоих двигателей. Алгоритм такой: с отклонением джойстика-2 от нейтрального до 100% (вправо или влево) уменьшается влияние джойстика-1 на свой двигатель - от 100% до 0%. Т.е. при джойстике-2 100% или (-100%) работает только один двигатель на максимум, независимо от джойстика-1 (его влияние 0%).
Этот алгоритм и для FORWARD и для BACKWARD.
комплект аппаратуры будет стоить дешевле, однозначно, скетч для управления авто можно взять тут
Согласен, на фрилансе в 5000 р оценили. Пробую пока сам. Ну, тут нет хорошего структурированного архива скетчей, у Гайвера на сайте в разы грамотней и полезней да и форум тоже есть с проектами. Рыскал, не нашел пока, хотя казалось бы, простая вещь.
хотя казалось бы, простая вещь.
В том и дело
простая, не простая, но иметь железки и макет собирать всё равно надо. поэтому предлагаю свои услуги за 2к. man9913@mail.ru
Хорошо, когда не надо строить дом и кормить семью.
простая, не простая, но иметь железки и макет собирать всё равно надо.
С этим проблем нет, написал в начале. А вот с кодингом дело хуже обстоит. Спасибо за ответ, это более привлекательное предложение.
Пока запускаю без радиомодуля, по скетчу из гайверского архива. Вот рабочий вариант (стандартный: каждый стик на каждый мотор) без радиомодуля с добавкой разгона ШИМа (моторы пищали) и плавностью изменения скорости.
01
/*
02
Пример управления двумя моторами
03
*/
04
#include "GyverMotor.h"
05
GMotor motor1(DRIVER2WIRE, 2, 3, HIGH);
06
GMotor motor2(DRIVER2WIRE, 4, 5, HIGH);
// поменял 11-й на 5-й (ради эксперимента, т.к. 11-й занят радиомодулем)
07
// используем оба ШИМа таймера 2 (пины 3 и 11)
08
09
void
setup
() {
10
11
// разгоняем ШИМ на пинах 3 и 11 (atmega328) до 31 кГц
12
TCCR2B = 0b00000001;
// x1
13
TCCR2A = 0b00000001;
// phase correct
14
15
// Пины D5 и D6 - 31.4 кГц
16
TCCR0B = 0b00000001;
// x1
17
TCCR0A = 0b00000001;
// phase correct
18
19
// минимальный сигнал (по модулю), который будет подан на мотор
20
// Избавляет от ситуаций, когда мотор покоится и "пищит"
21
//////////////////////////////// не заладилось: самопроизвольное вращение, нет нормального управления
22
// motor1.setMinDuty(150);
23
// motor2.setMinDuty(150);
24
25
// установка скорости изменения скорости (ускорения) мотора (плавность)
26
motor1.setSmoothSpeed(120);
27
motor2.setSmoothSpeed(120);
28
29
30
// ключ на старт!
31
motor1.setMode(FORWARD);
32
motor2.setMode(FORWARD);
33
}
34
35
void
loop
() {
36
// потенциометр на А0
37
// преобразуем значение в -255.. 255
38
int
val_1 = 255 - analogRead(0) / 2;
39
40
// потенциометр на А1
41
// преобразуем значение в -255.. 255
42
int
val_2 = 255 - analogRead(1) / 2;
43
44
motor1.setSpeed(val_1);
45
motor2.setSpeed(val_2);
46
// в данном случае мотор будет остановлен в среднем положении рукоятки
47
// и разгоняться в противоположные скорости в крайних её положениях
48
49
delay(10);
// задержка просто для "стабильности"
50
}
Теперь надо искать-думать над логикой. 1. Управление обоих мотором одним стиком. 2. Задействование второго стика как регулятора % между двумя моторами. Надеюсь, ссылка выше от ua6em мне поможет. Или закажу man9913-у, все же время не резиновое.
Теперь надо искать-думать над логикой. 1. Управление обоих мотором одним стиком. 2. Задействование второго стика как регулятора % между двумя моторами. Надеюсь, ссылка выше от ua6em мне поможет. Или закажу man9913-у, все же время не резиновое.
:-)
Лучше закажите сразу за 2 штуки три логики работы: одним джойстиком управлять, двумя - независимо каждым мотором и вашу.
Пожалуй, так и сделаю. О man9913 есть полож. отзывы.
Теперь надо искать-думать над логикой. 1. Управление обоих мотором одним стиком. 2. Задействование второго стика как регулятора % между двумя моторами. Надеюсь, ссылка выше от ua6em мне поможет. Или закажу man9913-у, все же время не резиновое.
:-)
Лучше закажите сразу за 2 штуки три логики работы: одним джойстиком управлять, двумя - независимо каждым мотором и вашу.
всё уже давно придумано до нас, в ссылке есть исходник управления двигателями, это рабочий вариант, пропорции подобраны под сцепление с колёсами как там получится на винтах не знаю, может надо будет задействовать "танковый разворот" он как вариант в скетчах есть, все проблемы ожидают с радиоканалом недаром местные старшие их мешками на помойку вынесли и взяли другие девайсы на этот диапазон...
Рабочий код приёмника и передатчика могу скинуть за скромную бутылку коньяку )))
PS после аппаратуры управления (их у меня несколько начиная с Футабы) - два шага назад )))
PPS сдаётся мне, что надо как на корабликах делать раздрай - их есть у меня тоже
Да, наверняка есть, но понимаете, там ведь придется читать кучу текста, пояснений, потом вырезать нужные куски кода, подстраивать их под себя, подключать, пробовать... Это еще если найдешь и поймешь что там и где. Иногда быстрей самому изучить с нуля или заказать, если цена сопоставима с экономией твоего времени.
... все проблемы ожидают с радиоканалом недаром местные старшие их мешками на помойку вынесли и взяли другие девайсы на этот диапазон...
PS после аппаратуры управления (их у меня несколько начиная с Футабы) - два шага назад )))
Ну я вообще поклонник блютуз. Управляем с ПК, телефона и "железным" пультом. По моему мнению он явно должен быть одноруким :-)
Да, наверняка есть, но понимаете, там ведь придется читать кучу текста, пояснений, потом вырезать нужные куски кода, подстраивать их под себя, подключать, пробовать... Это еще если найдешь и поймешь что там и где. Иногда быстрей самому изучить с нуля или заказать, если цена сопоставима с экономией твоего времени.
вы большой оптимист если думаете одолеть авто на винтах без мучений, 100500 аналогичной конструкции здесь никто не делал, написать рабочий код - да, но довести до хотелок - отнюдь, на отладку раздрая у меня ушло полгода )))
PS для соревнований
Да? А в чем проблема-то? В весе? У меня легкая конструкция. Ну, как запасной вариант - лодка.
1. Гувер делал проект с радиоуправляемой машиной, плохо ищете.
2. Трансиверы nRF24L01+ и голубой зуб работают в диапазоне 2.4 ГГц. Этот диапазон очень сильно засран бытовым вайфаем, условия приёма будут тяжёлыми. Не рассчитывайте что посылки будут доходить целыми в реальном времени. Я подобное управление делаю на кнопках, которые передают абсолютное состояние, как в кондиционерах.
3. Вы на форуме, который слегка модерируется. Одним человеком или двумя, если мне не изменяет память. На этом форуме пять разделов, в трёх из которых - 950 страниц, на каждой из которых по 25 тем. Вас удивляет что возникла помойка, которую невозможно разобрать? У меня есть граббер, который умеет сосать списки тем, размечая в диалект xml, и сами темы в виде обычного html как есть. Могу дать, выкачаете и может что найдёте. Системные требования - php 5.2, js 1.1 (на стабильной сборке денвера прошлого поколения пашет, во всяком случае).
1. Гувер делал проект с радиоуправляемой машиной, плохо ищете.
смотрел я его проект, он как обычно на предупреждения компилятора, о чём не раз тут вещал Евгений Петрович - забил, а напрасно )))
Поделись грабером
PS против Гайвера ничего не имею, даже больше, нравится его подача материала )))
Такие nRF24L01+, как на картинке вверху, ещё более-менее нормально работают в пределах квартиры (на 250кб/с) с редкими потерями кадров. Но если планируете использовать на бОльшие расстояния, то думаю нужно что-то другое.
Можно попробовать похожие модули nRF24L01+, но с дополнительным чипом-усилителем ВЧ и внешней антенной. Типа таких (1-й вариант): https://aliexpress.ru/item/32517849393.html
Я себе один такой купил "на попробовать", но пока руки не дошли.
Если хотите надежности, тогда Zigbee с технологией мэш https://aliexpress.ru/item/1005003302284233.html
Если хотите надежности, тогда Zigbee с технологией мэш https://aliexpress.ru/item/1005003302284233.html
А у него чего сеть из пультов !? :)
Если хотите надежности, тогда Zigbee с технологией мэш https://aliexpress.ru/item/1005003302284233.html
А у него чего сеть из пультов !? :)
нет, из наземных станций )))
ua6em
1. Нужны списки тем в таком формате:
1
<script type=text/javascript src=
"utils/grabcall.js"
></script>
2
<entry><href>/forum/obshchii/pomogite-novichku-7</href><hdr>помогите новичку</hdr></entry>
3
<entry><href>/forum/obshchii/atmel-studio</href><hdr>Атмел Студио</hdr></entry>
4
<entry><href>/forum/proekty/transistor-tester-arduino</href><hdr>transistor tester</hdr><qty>16</qty></entry>
в файлах .html, чтобы их можно было открывать на localhost в обозревателе. Тег <entry> невидимый, мешаться не будет.
Рядом (там где хтмл файлы) создать каталоги utils, data, в utils положить файлы grabcall.js и grabproc.php
Если каталог data не существует то работать не захочет (не умеет создавать этот каталог). Файлы будут называться testNN.htl, где test - имя файла со списком (оно берётся из адресной строки). Эти файлы это обычный хмл, их можно переименовать в html и читать, но поудобнее будет если маленько причесать и раскрасить. Нечётные посты имеют другой класс, чтобы можно было чередовать цвет, так читать удобнее.
01
var grablist=[];
02
var i_grab=0;
03
var grab_process=
false
;
04
var grabber=
new
XMLHttpRequest();
05
var grab_restrict_retry=
false
;
06
var grab_restrict_timer=undefined;
07
var gpos=undefined;
08
var data=undefined;
09
10
function grab(){
11
if
(i_grab==grablist.length)
return
;
12
if
(grab_restrict_retry)
return
;
13
if
(!grab_process){
14
grab_process=
true
;
15
i_grab++;
16
gpos.innerHTML=i_grab+
"/"
+grablist.length;
17
grab_exec();
18
grabber.onreadystatechange=function(){
19
if
(grabber.readyState!=4 || grabber.status!=200)
return
;
20
grab_process=
false
;
21
if
(grab_restrict_timer!=undefined) clearTimeout(grab_restrict_timer);
22
grab_restrict_retry=
false
;
23
gpos.style.color=
"#000"
;
24
setTimeout(function(){grab();},150);
25
};
26
}
else
grab_exec();
27
}
28
function grab_exec(){
29
var s=grablist[i_grab-1];
30
gpos.style.color=
"#f00"
;
31
grabber.open(
"POST"
,
"utils/grabproc.php?r="
+Math.random(),
true
);
// mb index/utils/grabproc.php?r=
32
grabber.send(s);
33
grab_restrict_retry=
true
;
34
grab_restrict_timer=setTimeout(function(){
35
grab_restrict_retry=
false
;
36
clearTimeout(grab_restrict_timer);
37
},5000);
38
}
39
function spawn_tools(){
40
gpos=document.createElement(
"div"
);
// req starter
41
gpos.setAttribute(
"id"
,
"gpos"
);
42
gpos.style.font=
"20pt arial"
;
43
document.body.appendChild(gpos);
44
gpos.innerHTML=
"Launch"
;
45
gpos.addEventListener(
"click"
,function(){
46
gpos.removeEventListener(
"click"
,arguments.callee,
false
);
47
grab();
48
});
49
}
50
document.addEventListener(
"DOMContentLoaded"
,function(){
51
spawn_tools();
52
var m=document.getElementsByTagName(
"entry"
).length;
53
for
(var k=0;k<m;k++){
54
data=document.getElementsByTagName(
"entry"
)[k].children;
55
var n=0;
56
if
(data.length==3) n=eval(data[2].innerHTML);
57
var qtarg=
"http___arduino_ru"
+data[0].innerHTML;
58
grablist.push(qtarg);
59
for
(var i=1;i<n+1;i++) grablist.push(qtarg+
"?page="
+i);
60
document.getElementsByTagName(
"entry"
)[k].innerHTML=
""
;
61
}
62
gpos.innerHTML+=
" (tot: "
+grablist.length+
")"
;
63
});
01
<?php
02
function
curlquery(
$url
){
03
$ch
=curl_init();
04
curl_setopt(
$ch
,CURLOPT_URL,
$url
);
05
curl_setopt(
$ch
,CURLOPT_AUTOREFERER,true);
06
curl_setopt(
$ch
,CURLOPT_RETURNTRANSFER,true);
07
curl_setopt(
$ch
,CURLOPT_FOLLOWLOCATION,true);
08
curl_setopt(
$ch
,CURLOPT_HEADER,true);
09
curl_setopt(
$ch
,CURLOPT_USERAGENT,
'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'
);
10
$rawdata
=curl_exec(
$ch
);
11
curl_close(
$ch
);
12
return
$rawdata
;
13
}
14
function
lz(
$n
){
15
if
(
$n
<10)
return
'0'
.
$n
;
else
return
$n
;
16
}
17
$targ
=
file_get_contents
(
'php://input'
);
18
if
(isset(
$_SERVER
[
'HTTP_REFERER'
])){
19
$fname
=
$_SERVER
[
'HTTP_REFERER'
];
20
$fname
=
str_replace
(
substr
(
$fname
,0,
strrpos
(
$fname
,
'/'
)+1),
''
,
$fname
);
21
$fname
=
str_replace
(
'.htm'
,
'.htl'
,
$fname
);
22
}
23
$fname
=
'../data/'
.
$fname
;
24
$new_fname
=
$fname
;
25
$new_flag
=false;
26
$maxsize
=700000;
27
if
(
file_exists
(
$fname
) &&
filesize
(
$fname
)>
$maxsize
){
28
$n
=1;
29
while
(
file_exists
(
$new_fname
=
str_replace
(
'.htl'
,lz(
$n
).
'.htl'
,
$fname
)) &&
filesize
(
$new_fname
)>
$maxsize
)
$n
++;
30
$new_flag
=true;
31
}
32
$cfg_file
=
'grablast.json'
;
33
if
(
file_exists
(
$cfg_file
)){
34
$cfg_str
=
file_get_contents
(
$cfg_file
);
35
$cfg_str
=json_decode(
$cfg_str
);
36
$last_thread
=
$cfg_str
[0];
37
$hide_counter
=
$cfg_str
[1];
38
$last_odd
=
$cfg_str
[2];
39
}
else
{
40
$last_thread
=
''
;
41
$hide_counter
=0;
42
$last_odd
=false;
43
}
44
if
(!
$new_flag
)
$new_fname
=
str_replace
(
'.htl'
,
'00.htl'
,
$new_fname
);
45
$fp
=
fopen
(
$new_fname
,
'a+'
);
46
if
(
$targ
!=
""
){
47
$rawpage
=curlquery(
$targ
);
48
if
(
$rawpage
){
49
$pos_s
=
strpos
(
$rawpage
,
'<title>'
)+7;
// thread
50
$pos_e
=
strpos
(
$rawpage
,
' | '
,
$pos_s
);
51
$thrtitle
=
substr
(
$rawpage
,
$pos_s
,
$pos_e
-
$pos_s
);
52
if
(
$last_thread
!=
$thrtitle
||
$new_flag
){
53
fwrite(
$fp
,
'<thread><h2>'
.iconv(
'utf-8'
,
'windows-1251'
,
$thrtitle
).
'</h2></thread>'
.PHP_EOL);
54
$last_thread
=
$thrtitle
;
55
}
56
$searchpos
=0;
57
$x
=0;
58
while
(
$x
<51){
59
$hide_counter
++;
60
$last_odd
=!
$last_odd
;
61
$hide_id
=
'hide_'
.
$hide_counter
;
62
$x
++;
63
$pos_s
=
strpos
(
$rawpage
,
'author-pane-line author-name'
,
$searchpos
);
64
$pos_e
=
strpos
(
$rawpage
,
' </div>'
,
$pos_s
);
65
$searchpos
=
$pos_e
;
66
$author
=
substr
(
$rawpage
,
$pos_s
+39,
$pos_e
-
$pos_s
-44);
67
$pos_s
=
strpos
(
$rawpage
,
'<div class="content">'
,
$searchpos
);
68
$pos_e
=
strpos
(
$rawpage
,
'forum-post-footer clear-block'
,
$pos_s
);
// start
69
$searchpos
=
$pos_e
;
70
$posttext
=
substr
(
$rawpage
,
$pos_s
+0,
$pos_e
-
$pos_s
-43);
71
$posttext
=
str_replace
(
'<div class="content">'
,
'<div class="content" id="'
.
$hide_id
.
'">'
,
$posttext
);
// unique hide id
72
$posttext
=
str_replace
(
'<strong'
,
'<b'
,
$posttext
);
73
$posttext
=
str_replace
(
'</strong'
,
'</b'
,
$posttext
);
74
$posttext
=
str_replace
(
'<em'
,
'<i'
,
$posttext
);
75
$posttext
=
str_replace
(
'</em'
,
'</i'
,
$posttext
);
76
$posttext
=
str_replace
(
' '
,
' '
,
$posttext
);
77
$posttext
=
str_replace
(
chr
(9),
' '
,
$posttext
);
78
for
(
$i
=0;
$i
<5;
$i
++)
$posttext
=
str_replace
(
' '
,
' '
,
$posttext
);
79
$posttext
=
str_replace
(
'/sites/default/files/u'
,
'http___arduino_ru/sites/default/files/u'
,
$posttext
);
80
if
(
strpos
(
$rawpage
,
'author-pane-line author-name'
,
$searchpos
)===false)
$x
=70;
// end
81
$postdata
=iconv(
'utf-8'
,
'windows-1251'
,
'<postdata><postauthor>'
.
$author
.
'</postauthor>'
.
$posttext
.
'</postdata>'
).PHP_EOL;
82
$postdata
=
str_replace
(
' <p>'
,
'<p>'
,
$postdata
);
83
$postdata
=
str_replace
(
' </div>'
,
'</div>'
,
$postdata
);
84
$postdata
=
str_replace
(
'<p>'
.
chr
(160).
'</p>'
,
''
,
$postdata
);
85
$postdata
=
str_replace
(
chr
(10).
chr
(10),
chr
(10),
$postdata
);
86
$postdata
=
str_replace
(
chr
(160),
''
,
$postdata
);
87
if
(
$last_odd
)
$postodd
=
"post_odd"
;
else
$postodd
=
"post_even"
;
88
$postdata
=
str_replace
(
'<div class="content"'
,
'<div class="content '
.
$postodd
.
'"'
,
$postdata
);
89
fwrite(
$fp
,
$postdata
);
90
}
91
}
92
$cfg_str
=
array
(
$last_thread
,
$hide_counter
,
$last_odd
);
93
file_put_contents
(
$cfg_file
,json_encode(
$cfg_str
),LOCK_EX);
94
}
95
fclose(
$fp
);
96
?>
В урлах двоеточия точки косые черты заменены, чтобы парсер ссылок на форуме не агрился, их исправить.
2. Открыть сайт localhost/вашкаталог/text.htm
Зачем-то был вариант с путём localhost/вашкаталог/index/text.htm, то есть всё что относилось к спискам тем было переложено в подкаталог. Скорее всего потому что у меня старые списки были свалены отдельно в попытке разобрать по ключевым словам комплектухи (всё с цифрами 9341, 2004, 1602 к экранам и т п).
На странице будет надпись из количества подлежащих скачиванию страниц сделанных/всего. На неё нажать мышкой. Активная красная. Если оба номера равны всего и надпись чёрная - значит готово. Если залагало/оборвалось, то автосохранется в файле grablast.json, потом можно заново открыть, нажать и продолжится. Я бы его конешно переделал под более цивильный вид и чтобы без js (чтобы работало интерактивно команднострочно), но это у меня, скажем так, щас неактивный проект. Если переделаю то выложу в отдельную тему.
3. Как делать списки тем
curl -L -o file.ext http___arduino_ru/forum/6
потом curl -L -o файлтемы URLссылкинатему
на последние страницы придётся в обозревателе понажимать.
<qty> - количество страниц в теме минус 1 (потому что вторая страница содержит в URL двойку, но первая не содержит единицу)
Длину тем придётся попарсить (выуживая из страниц, сграбленных в разделах). Автоматизировать bat-файлами. Разбирать тексты можно каким-нибудь редактором с макросами. Мне лично нравится FAR т. к. он универсальный и я могу лазить в файлы из панелей, не покидая его окна, то есть получаю бесшовную работу как с содержимым диска, так и самих файлов (не надо альттабаться). Но дело вкуса и я ни к чему не принуждаю.
Лайфхак для машин с антивирусом в агрессивном режиме: не стоит пытаться что-то запускать из php. лучше писать bat, который потом запустить руками. Если происходит цепной запуск "пользователь->php->bat->curl например" то антивирусы агрятся. Любые. Да неудобняк с curl, но делал для себя и потому граббер полуавтоматический а не автоматический. Я вообще не спец в написании релизных прог, делаю в программе только то что мне впадлу/долго делать руками.
Если лень их составлять то эту работу я уже делал, но те списки по состоянию на 2018й год (если судить по атрибутам файлов). Их где-то полтора мегабайта, тоже если надо поделюсь, но актуальнее всё же будет забрать curl-ом новые.
UPD: конечные хтмлы режутся по ~700 килобайт, чтобы не лагало когда читаешь.
UPD: конечные хтмлы режутся по ~700 килобайт, чтобы не лагало когда читаешь.
TKS!
Посмотрел Гайверовскую библиотеку и рисунок, вот как-то не верится, что он не понимает, что при таком раскладе сигналов на пины на ШИМе влетает каждый период на активное торможение?
(при движении назад естественно)
Да, это ошибка, но видимо он экономит ШИМ выводы :-)
А говоря философически - большое число "покатушек-ходунов" имеют и сервоприводы и ШИМ управляемые моторы. Как бы хорошо иметь общую библиотеку на 20 ШИМ выводов и сервоприводов :-), не мешающих друг другу.
Да, это ошибка, но видимо он экономит ШИМ выводы :-)
А говоря философически - большое число "покатушек-ходунов" имеют и сервоприводы и ШИМ управляемые моторы. Как бы хорошо иметь общую библиотеку на 20 ШИМ выводов и сервоприводов :-), не мешающих друг другу.
ну да, пару ШИМ каналов, но и в библиотеке жеж аналогично...
Архат брал мегу, даже расширял ей память и в размерах ужимал значительно,
для сына пилил, на скоростные покатушки, у меги с этим получше