Вопрос

Я пытаюсь управлять своим автомобилем 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 (и другие имена функций) следующим образом:

  1. Местные новости: Есть ли какой-нибудь motor_stop определено в этой функции?Нет.Двигаемся дальше.
  2. Заключающий в себе: Определена ли эта функция внутри другой функции?Нет, значит, правило "вложения" не применяется.Двигаемся дальше.
  3. Глобальный: Есть ли какой-нибудь motor_stop определено на верхнем уровне программы?ДА.Нашел это.
  4. (Встроенный):Это правило вообще никогда не проверяется, потому что имя было найдено с помощью "глобального" правила.

Все ваши функции определены на верхнем уровне вашей программы, поэтому "глобальное" правило найдет их без необходимости 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

Парны в подписи вызова находятся там, чтобы показать свой парусмент функции

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top