Управление движением через браузер, что применить?
- Войдите на сайт для отправки комментариев
Всем привет!
Пожалуйста подскажите, каким образом можно управлять Ардуиной через браузер, с учетом непрерывного действия?
То есть, чтобы при нажатой кнопке "Вперед" непрерывно шла отправка нужного символа на последовательный порт.
Поясню, как я сейчас делаю:
1. Есть php-скрипт, пишущий через fwrite на COM3-порт символ "w", получая который, Ардуино включает нужный пин (драйвер мотора).
2. Скрипт вызывается через AJAX с HTML-страницы, таким образом:
<script type="text/javascript" language="javascript">
function makeRequest(url) {
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
// Читайте ниже об этой строке
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
http_request.onreadystatechange = function() { alertContents(http_request); };
http_request.open('GET', url, true);
http_request.send(null);
}
</script>
<!-- ================= -->
<!-- ТУТ КНОПКА ВПЕРЕД -->
<div style="width:250px;" align="center">
<img src="img/forward.png" title="Вперед" value="VPERED" onclick="makeRequest('send.php?symbol=VPERED')">
<!-- ТУТ КНОПКА ВПЕРЕД -->
<!-- ================= -->
</div>
До этого тестил с обычной <form></form>, где после нажатия кнопки браузер перекидывал на скрипт.
Но текущий AJAX-скрипт также не может решить задачу непрерывного управления, то есть, нажав кнопку (картинку), страница отправляет один раз "w" на COM3 и все, ждет, пока кнопку\картинку вновь не нажмут.
Аналогичная ситуация при использовании событий onMouseDown и onMouseOver - также, одинарное срабатывание. Если зажать кнопку\картинку, то событие идет один раз.
Скажите, возможно ли через браузер сделать что-то вроде события onPressed, чтобы браузер циклично, непрерывно исполнял код, пока нажата кнопка\картинка?
Если я правильно понимаю, чисто средствами JS это не сделать, т.к. JS очень изолирован от железа компьютера, поэтому стоит задача непрерывно вызывать php-скрипт, можно как-то это сделать?
Заранее большое спасибо!
навскидку такая идея:
непосредственно в функции makeRequest вызов php-скрипта поместить в бесконечный цикл, который выполнять в зависимости от флага, а флаг устанавливать в true по событию onMouseDown и в false по onMouseUp
Я не могу понять: когда вы посылаете w контроллеру, что происходит? Пойдет питание контроллеру? На сколько оно подастся? Установится ли флаг или что? Просто даже если у вас нету проблем и браузер посылает состояние нажатой кнопки, посмотрите как будет работать ваше "устройство" если просто запустить цикл на php например
for ($i=0;$i<100;$i++){ //тут ваша функция посылающая "w" контроллеру //потом задержка, так как иначе весь цикл пролетит за такт. usleep(200000);// 200 000 микросекунд = 200 милисекунд. }Я почти уверен, что ваше устройство будет дергаться.
Попробуйте сделать так:
Посылайте в МК вашу заветную "w" скриптом php выше, а в нем уже отлавливая w начинайте движение.
В МК нужно проверять если в течении 201 милисекунды не пришло команд, то останавливаемся.
201 утрированно, я бы скорей взял 300. Вобщем поэкспериментируйте с цифрами, добиваясь плавного движения.
Насчет дальнейшей реализации, я бы взглянул на WEB Sockets.
навскидку такая идея:
непосредственно в функции makeRequest вызов php-скрипта поместить в бесконечный цикл, который выполнять в зависимости от флага, а флаг устанавливать в true по событию onMouseDown и в false по onMouseUp
Что произойдет, если флаг остановиться не придет?
так это на совести ТС, что у него там происходит.
в техзадании просто сказано, что обязательно непрерывное действие, а уж он роботом по кухне ездит или у него реально экскаватор траншеи копает - хз. сие мне неведомо и последствия выходят за рамки вопроса
может у него наоборот, если все остановится - рванет чего-нибудь? :)
com, m0rjjj, большое спасибо за ответы!
C циклом в makeRequest попробую, интересная идея, спасибо!
morjjj, php-скрипт просто пишет в порт chr() символа, fwrite($fp, chr($symbol)). Ардуино в loop'е читает порт и если есть символ, то включает заданный пин, у меня самый простой вариант.
А js на HTML-странице интерфейса вызывает php-скрипт для управления через AJAX.
Но, как я уже писал в первом сообщении, у меня не получается делать "непрерывное нажатие", т.е. непрерывно вызывать php-скрипт через события JavaScript, пока кнопка нажата.
Возможно, есть какие-то типовые, применяемые ардуинщиками решения для управления через браузер, а я тут Америку пытаюсь открыть.
Большое спасибо!
Код HTML-страницы:
<!DOCTYPE html> <html dir="ltr" lang="ru-RU"> <head> <meta charset="UTF-8" /> <title>Управление Ардуино через браузер</title> <script type="text/javascript" src="javascript/jquery-1.7.2.min.js"></script> </head> <body> <script type="text/javascript" language="javascript"> function makeRequest(url) { var http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari, ... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType('text/xml'); // Читайте ниже об этой строке } } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } http_request.onreadystatechange = function() { alertContents(http_request); }; http_request.open('GET', url, true); http_request.send(null); } </script> <div style="width:250px;" align="center"> <img src="img/forward.png" title="Вперед" value="VPERED" onMouseOver="makeRequest('send.php?symbol=VPERED')"><br> <img src="img/left.png" title="Влево" value="LEFT" onMouseOver="makeRequest('send.php?symbol=LEFT')"> <img src="img/back.png" title="Назад" value="NAZAD" onMouseDown="makeRequest('send.php?symbol=NAZAD')"> <img src="img/right.png" title="Вправо" value="RIGHT" onMouseDown="makeRequest('send.php?symbol=RIGHT')"><br><br><br> <img src="img/action.png" title="Действие" value="ACTION" onMouseDown="makeRequest('send.php?symbol=ACTION')"> </div> </body> <html>Код php-скрипта:
<?php // Считываем полученный символ $curr = $_GET['symbol']; // Преобразовываем в ASCII-код switch ($curr) { // Буква w case 'VPERED': $symbol = '119'; break; // Буква s case 'NAZAD': $symbol = '115'; break; // Буква a case 'LEFT': $symbol = '97'; break; // Буква d case 'RIGHT': $symbol = '100'; break; // Буква z case 'ACTION': $symbol = '122'; break; // По-умолчанию пустой символ default: break; } // Открываем порт на запись $fp = fopen ("COM3", "w"); if (!$fp) { echo "<span style='color:red;'>Not open COM3 port!</span><br>"; } else { echo "<span style='color:green;'>COM3 port successfully opened!</span><br>"; echo "CURRENT SYMBOL IS: ".chr($symbol)."<br><br><br>"; // Отправляем в COM-порт символ fwrite($fp, chr($symbol)); } // Закрываем COM-порт fclose($fp); ?>Код скетча Ардуино:
// Управление светодиодиодами компьютера int relay1 = 8; int relay2 = 9; int relay3 = 6; int relay4 = 7; int relay5 = 10; char p; void setup() { Serial.begin(9600); pinMode(relay1, OUTPUT); pinMode(relay2, OUTPUT); pinMode(relay3, OUTPUT); pinMode(relay4, OUTPUT); pinMode(relay5, OUTPUT); } void loop() { // Если есть данные в последовательном порту if (Serial.available()) { // Считываем данные в переменную p = Serial.read(); // Если буква w if (p == 'w') { digitalWrite(relay1, HIGH); delay(500); digitalWrite(relay1, LOW); } // Если буква s else if (p == 's'){ digitalWrite(relay2, HIGH); delay(500); digitalWrite(relay2, LOW); } // Если буква a else if (p == 'a'){ digitalWrite(relay3, HIGH); delay(500); digitalWrite(relay3, LOW); } // Если буква d else if (p == 'd'){ digitalWrite(relay4, HIGH); delay(500); digitalWrite(relay4, LOW); } // Если буква z else if (p == 'z'){ digitalWrite(relay5, HIGH); delay(500); digitalWrite(relay5, LOW); } } }отпишитесь потом, получилось или нет, мне самому интересно стало
У вас в скетче delay, а это паразит. Объясню почему в вашем случае. Допустим вы зажали кнопку в браузере, и с интервалом в 500мс аяксом будет вызываться php скрипт, который пошлет в ком МК какой-то символ, на первый раз все сработает, а вот со вторым символом если он придет раньше чем ~500 мс в МК то эти 500мс МК будет простаивать, а если позже, то возможно реле дернется на 1~5мс.
В вашем случае я порекомендую попробывать такой алгорит. Если вы уже знакомы, как поменять deleay на millis то проблем у вас не возникнет. Делаем так:
1. заводим отдельный счетчик для каждой команды: например millisFront, millisBack, millisLeft и т.д.
2. Когда приходит символ с ком порта то вы как бы инкрементируете millisFront на 500 мс, а уже ниже проверяете если millisFront больше текущих millis то включаем реле, тем самым зная, что ему еще работать те самые 500мс, иначе - отключаем, т.к. он свое время просрочил.
Плюс возможно в том, что можно слать с браузера сразу несколько зажатых кнопок, и тем самым сразу ехать прямо и в лево. Но думаю это проблематично, лучше не стоит.
com, на Амперке посоветовали делать не непрерывно, а в два запроса - первый, на событие onMouseDown, непрерывная работа (переводим пин в HIGH), второй, на событие onMouseUp, сброс пина в LOW.
Получился такой рабочий вариант:
Интерфейс:
<!DOCTYPE html> <html dir="ltr" lang="ru-RU"> <head> <meta charset="UTF-8" /> <title>Управление Ардуино через браузер</title> <script type="text/javascript" src="javascript/jquery-1.7.2.min.js"></script> </head> <body> <script type="text/javascript" language="javascript"> function makeRequest(url) { var http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari, ... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType) { http_request.overrideMimeType('text/xml'); // Читайте ниже об этой строке } } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } http_request.onreadystatechange = function() { alertContents(http_request); }; http_request.open('GET', url, true); http_request.send(null); } </script> <div style="width:250px;" align="center"> <img src="img/forward.png" title="Вперед" value="VPERED" onMouseDown="makeRequest('send.php?symbol=w')" onMouseUp="makeRequest('send.php?symbol=w&cls=1')"><br> <img src="img/left.png" title="Влево" value="LEFT" onMouseDown="makeRequest('send.php?symbol=a')" onMouseUp="makeRequest('send.php?symbol=a&cls=1')"> <img src="img/back.png" title="Назад" value="NAZAD" onMouseDown="makeRequest('send.php?symbol=s')" onMouseUp="makeRequest('send.php?symbol=s&cls=1')"> <img src="img/right.png" title="Вправо" value="RIGHT" onMouseDown="makeRequest('send.php?symbol=d')" onMouseUp="makeRequest('send.php?symbol=d&cls=1')"><br><br><br> <img src="img/action.png" title="Действие" value="ACTION" onMouseDown="makeRequest('send.php?symbol=z')" onMouseUp="makeRequest('send.php?symbol=z&cls=1')"> </div> </body> <html>PHP-скрипт:
<?php // Считываем полученный символ и преобразуем в ASCII-код $curr = ord($_GET['symbol']); // Если есть параметр cls=1, то отнимаем от ASCII-кода 32 (буква в большом регистре, сброс пина в LOW) $cls = $_GET['cls']; if ($cls == 1) { $curr = $curr-32; } // Открываем порт на запись $fp = fopen ("COM3", "w"); if (!$fp) { echo "<span style='color:red;'>Not open COM3 port!</span><br>"; } else { echo "<span style='color:green;'>COM3 port successfully opened!</span><br>"; // Отправляем в COM-порт символ fwrite($fp, chr($curr)); } // Закрываем COM-порт fclose($fp); ?>Скетч:
// Управление Ардуино через браузер int blue = 8; int red = 9; int green = 6; int tblue = 7; char p; void setup() { Serial.begin(9600); pinMode(blue, OUTPUT); pinMode(red, OUTPUT); pinMode(green, OUTPUT); pinMode(tblue, OUTPUT); } void loop() { // Если есть данные в последовательном порту if (Serial.available()) { // Считываем данные в переменную p = Serial.read(); // Если буква w if (p == 'w') { digitalWrite(blue, HIGH); } // Если буква W if (p == 'W') { digitalWrite(blue, LOW); } // Если буква s else if (p == 's'){ digitalWrite(red, HIGH); } // Если буква S else if (p == 'S'){ digitalWrite(red, LOW); } // Если буква a else if (p == 'a'){ digitalWrite(green, HIGH); } // Если буква A else if (p == 'A'){ digitalWrite(green, LOW); } // Если буква d else if (p == 'd'){ digitalWrite(tblue, HIGH); } // Если буква D else if (p == 'D'){ digitalWrite(tblue, LOW); } // Если буква z else if (p == 'z'){ digitalWrite(blue, HIGH); digitalWrite(green, HIGH); } // Если буква Z else if (p == 'Z'){ digitalWrite(blue, LOW); digitalWrite(green, LOW); } } }m0rjjj, Вы правы про delay().
В варианте с непрерывной работой по onMouseDown (мое сообщение выше) это решается и одновременно могут работать несколько кнопок (хоть все).
Теперь осталась только такая проблема - если вдруг потеряется связь, а сигнала на LOW не поступит, то робот будет выполнять действие, пока не потратит всю батарейку.
Можно сделать через:
if (p == "w") { digitalWrite(relay1, HIGH); delay(60000); // работает 1 минуту digitalWrite(relay1, LOW); }, но если кнопка будет нажата более, чем минуту, то Ардуино переведет пин в LOW и нужно будет вновь нажимать кнопку.
com, на Амперке посоветовали делать не непрерывно, а в два запроса - первый, на событие onMouseDown, непрерывная работа (переводим пин в HIGH), второй, на событие onMouseUp, сброс пина в LOW.
Я вам указал про возможную проблему, в отсутствии сигнала от mouseUp. Решать все-равно вам, оба варианта рабочие, отпишитесь потом что получилось.
m0rjjj, с двумя запросами на onMouseDown, onMouseUp работает, его взял для робота :)
Теперь с блютусом буду пробовать беспроводное управление.