Python, Webiopi и Raspberry Pi
-
20-12-2019 - |
Вопрос
Я пытаюсь управлять своим автомобилем Raspberry Pi с помощью беспроводной сети и webiopi.Базовая функция работает нормально - есть интерфейс, в котором я нажимаю fwd, и машина едет вперед, а когда я отпускаю кнопку, она останавливается.
Теперь я хочу встроить ультразвуковой датчик расстояния, чтобы, когда я еду вперед, машина останавливалась, когда перед ней что-то есть.У меня получается так, что когда я нажимаю кнопку fwd, машина трогается с места и останавливается, когда что-то находится в пределах досягаемости, но останавливается только тогда, когда что-то находится в пределах досягаемости, а не когда я отпускаю кнопку.Мой цикл while каким-то образом зацикливается (зависает) и не считывает функцию release button из webiopi.
Может кто-нибудь, пожалуйста, помочь - занимаюсь этим уже несколько дней и не уверен, где я ошибаюсь:-(
Вот цикл из моего скрипта на Python:
def go_forward(arg):
global motor_stop, motor_forward, motor_backward, get_range
print "Testing"
print mousefwd()
while (arg) == "fwd":
print (arg)
direction = (arg)
dist = get_range()
print "Distance %.1f " % get_range()
if direction == "fwd" and get_range() < 30:
motor_stop()
return
else:
motor_forward()
А вот код из моего вызова функции webiopi:
function go_forward() {
var args = "fwd"
webiopi().callMacro("go_forward", args);
}
function stop1() {
var args = "stop"
webiopi().callMacro("go_forward", args);
webiopi().callMacro("stop");
}
Вот как у меня это сейчас, но все еще не работает (я полный нуб :-)) :
def go_forward(arg):
global motor_stop, motor_forward, motor_backward, get_range
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % get_range()
if get_range() < 30:
motor_stop()
elif direction == "fwd":
motor_forward()
else:
motor_stop()
Может быть, небольшой шаг вперед.Видите, что webipi использует свой собственный "цикл", и я добавил код цикла, чтобы проверить состояние GPIO двигателя и расстояние, и работает ли двигатель, и если расстояние слишком короткое, то остановитесь.Теперь машина движется, когда я нажимаю кнопку "Вперед", и останавливается, когда я отпускаю ее, а при движении вперед и расстоянии менее 30 см она останавливается.Единственная проблема заключается в том, что когда расстояние слишком короткое и я нажимаю кнопку переадресации слишком быстро несколько раз, я теперь получаю "GPIO.output(Echo, 1) _webiopi.GPIO.Исключение InvalidDirectionException:Канал GPIO не является выводом" ошибка :-( .
Теперь код выглядит следующим образом:
def go_forward(direction):
motor_forward()
def loop():
if get_range() < 30 and GPIO.digitalRead(M1) == GPIO.HIGH:
stop()
print "stop"
sleep(1)
Решение
Я отвечу на вашу главную проблему через минуту, но сначала я хочу упомянуть кое-что, что вы делаете как новичок в Python, что делает вашу жизнь более сложной, чем это должно быть.
Нет никакой необходимости в global
оператор, который у вас есть в начале вашей функции.В Python вам нужно только использовать global
заявление, если вы хотите писать к глобальной переменной.Если все, что вам нужно сделать, это Читать переменную или вызовите функцию, тогда отпадет необходимость в global
заявление.Любые имена, используемые в вашей функции, будь то имена переменных или функций, будут ищутся в следующем порядке:локальный, охватывающий, глобальный, встроенный."Local" означает имена, определенные внутри вашей функции, например, ваш direction
переменная."Заключающий" - это правило, используемое, когда вы определяете функцию внутри другой функции.Это полезно во многих ситуациях, но это немного продвинутая тема, и вам пока не нужно беспокоиться об этом."Глобальный" означает имена (переменных, или функций, или классов), определенные на верхнем уровне вашей программы, такие как ваш motor_stop
функция среди прочих.И, наконец, "встроенный" означает встроенные имена Python, такие как str
или int
или file
.
Так что, если вы не учли global
оператор, тогда Python выполнит поиск по имени motor_stop
(и другие имена функций) следующим образом:
- Местные новости: Есть ли какой-нибудь
motor_stop
определено в этой функции?Нет.Двигаемся дальше. - Заключающий в себе: Определена ли эта функция внутри другой функции?Нет, значит, правило "вложения" не применяется.Двигаемся дальше.
- Глобальный: Есть ли какой-нибудь
motor_stop
определено на верхнем уровне программы?ДА.Нашел это. - (Встроенный):Это правило вообще никогда не проверяется, потому что имя было найдено с помощью "глобального" правила.
Все ваши функции определены на верхнем уровне вашей программы, поэтому "глобальное" правило найдет их без необходимости global
заявление.Это должно немного упростить вашу жизнь.
Теперь перейдем к вашему главному вопросу:почему ваш код постоянно зацикливается.Это потому, что условие теста ваше while
цикл никогда не станет ложным.Вы зацикливаетесь на while direction == "fwd"
, и код внутри while
цикл никогда не изменяет direction
переменная.Таким образом, каждый раз, когда он достигает конца цикла, он возвращается, чтобы снова проверить условие.Тот Самый direction
переменная по-прежнему содержит строку "fwd"
, и таким образом, цикл while выполняется во второй раз.Затем direction
переменная по-прежнему содержит строку "fwd"
, и так это повторяется в третий раз.И так далее, и тому подобное.
Один из способов выйти из while
цикл, когда вы хотите, чтобы он завершился, состоял бы в том, чтобы установить direction
переменная к чему-то другому, например "stop"
, когда ты захочешь остановиться.(Например, после того, как вы позвоните motor_stop()
).Другим способом было бы использовать return
инструкция для выхода из функции в этот момент.Но мое предложение состояло бы в том, чтобы использовать break
вместо этого используется оператор, который означает "На этом этапе немедленно выйдите из цикла, в котором я нахожусь". Это работает с обоими while
петли и for
циклы, и это очень полезное утверждение, о котором нужно знать.Похоже, ты хочешь, чтобы твой while
цикл для выхода в любой момент, когда вы вызываете motor_stop()
, итак , есть два места, куда вы бы поместили break
заявление:
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % get_range()
if get_range() < 30:
motor_stop()
break
elif direction == "fwd":
motor_forward()
# No break statement here, so the while loop continues
else:
motor_stop()
break
Есть еще несколько изменений, которые я бы предложил внести.Сначала вы звоните get_range()
три раза в вашем цикле, но на самом деле вам нужно вызвать его только один раз.Вы уже присвоили его результат a dist
переменная, так почему бы не использовать эту переменную?
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
elif direction == "fwd":
motor_forward()
# No break statement here, so the while loop continues
else:
motor_stop()
break
И, во-вторых, нет никакого способа проникнуть внутрь while
цикл для direction
нет быть "fwd", так что окончательный else
является ненужным, и ваша функция может стать:
def go_forward(arg):
print "Testing"
direction = arg
while direction == "fwd":
print arg
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
else:
motor_forward()
Наконец, у вас есть параметр функции с именем arg
, это имя, которое ничего не говорит вам о том, для чего оно используется.Вы немедленно присваиваете его переменной с именем direction
, что является гораздо лучшим названием.Так почему бы не использовать это в качестве имени параметра в первую очередь?Не существует правила, в котором указывались бы параметры функции должен будет называться "arg";их можно называть как угодно (за исключением одного из зарезервированных в Python слов типа break
или if
).Итак, давайте дадим вашей функции более осмысленное имя параметра, и это еще больше упростит ее:
def go_forward(direction):
print "Testing"
while direction == "fwd":
print direction
dist = get_range()
print "Distance %.1f " % dist
if dist < 30:
motor_stop()
break
else:
motor_forward()
Там.Это намного легче прочитать и понять, и это должно решить проблему, с которой вы столкнулись в своем while
цикл не завершается, когда автомобиль подъезжает слишком близко к объекту.
(Я все еще вижу одну возможную проблему, которая заключается в том, что цикл while может не завершиться, пока автомобиль движется вперед, даже если вы отпустили кнопку "вперед", но я должен был бы увидеть ваш motor_forward()
код, чтобы знать, как решить эту проблему.Это может быть так же просто, как поместить break
заявление после motor_forward()
, и в этом случае действительно не было бы необходимости в while
цикл вообще - но я должен был бы знать, как ваш motor_forward()
код взаимодействует с webiopi и показывает, как работает код обработки событий webiopi.Ни о чем из этого я прямо сейчас не знаю, поэтому я собираюсь ответить на те проблемы, на которые я могу ответить сейчас, даже если мой ответ неполон, вместо того, чтобы оставить вас вообще без ответа.)
Редактирование Марком: Вот код motor_forward:
def motor_forward():
GPIO.output(M1, GPIO.HIGH)
GPIO.output(M2, GPIO.LOW)
string = "echo 0=130 > /dev/servoblaster"
os.system(string)
Другие советы
Попробуйте это - вы всегда останавливаетесь на диапазоне, но можете захотеть остановиться на направлении
if get_range() < 30:
motor_stop()
elif direction == "fwd":
motor_forward()
else:
motor_stop()
.
BTW Вам не нужен (arg) только arg, когда вы ссылаетесь на него
Печать Arg
Парны в подписи вызова находятся там, чтобы показать свой парусмент функции