I am trying to control my Raspberry Pi car via wireless and webiopi. The basic function works fine - have the interface where I click fwd and the car will go forward and when I release the button it will stop.
I now want to integrate the Ultrasonic distance sensor so that when I drive forward, the car should stop when something is in front of it. I have it going where when I click to fwd button, the car will drive and stop when something is in range but it will only stop when something is in range and not when I release the button. My while loop is somehow looping (stuck) and not reading the release button function from webiopi.
Can somebody please help - been at it for days now and not sure where I am going wrong :-(
Here is the loop from my python script:
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()
And here is the code from my webiopi function call:
function go_forward() {
var args = "fwd"
webiopi().callMacro("go_forward", args);
}
function stop1() {
var args = "stop"
webiopi().callMacro("go_forward", args);
webiopi().callMacro("stop");
}
This is how I have it now but still not working (I am a total noob :-) ) :
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()
Maybe a slight step forward. See that webipi uses its own 'loop' and I added the loop code to check what the status of the motor GPIO's are and the distance and if the motor is running and if the distance is too short then stop. Car moves now when I press the forward button and stops when I release it and when moving forward and distance is less then 30cm it will stop. Only problem is that when the distance is too short and I press the forward button too quickly multiple times, I now get a "GPIO.output(Echo,1) _webiopi.GPIO.InvalidDirectionException: The GPIO channel is not an OUTPUT" error :-( .
The Code looks now like this:
def go_forward(direction):
motor_forward()
def loop():
if get_range() < 30 and GPIO.digitalRead(M1) == GPIO.HIGH:
stop()
print "stop"
sleep(1)
I'll answer your main problem in a minute, but first I want to mention something you're doing as a Python beginner, which is making your life more complicated than it needs to be.
There's no need for the
global
statement you have at the start of your function. In Python, you only need to use theglobal
statement if you want to write to a global variable. If all you need to do is read the variable, or call the function, then there's no need for theglobal
statement. Any names used in your function, whether they're names of variables or names of functions, will be searched for in the following order: local, enclosing, global, builtin. "Local" means names defined inside your function, like yourdirection
variable. "Enclosing" is a rule used when you define a function inside another function. This is useful in many situations, but is a bit of an advanced topic and you don't need to worry about it for now. "Global" means names (of variables, or functions, or classes) defined at the top level of your program -- such as yourmotor_stop
function among others. And finally, "builtin" means Python's built-in names, likestr
orint
orfile
.So if you left out the
global
statement, then Python would search for the namemotor_stop
(and the other function names) as follows:motor_stop
defined in this function? No. Moving on.motor_stop
defined at the top level of the program? Yes. Found it.All of your functions are defined at the top level of your program, so the "global" rule will find them with no need for the
global
statement. This should make your life a little simpler.Now for your main question: why your code is looping forever. That's because the test condition your
while
loop will never become false. You are looping onwhile direction == "fwd"
, and the code inside thewhile
loop never changes thedirection
variable. So every time it reaches the end of the loop, it goes back to test the condition again. Thedirection
variable still contains the string"fwd"
, and so the while loop runs a second time. Then thedirection
variable still contains the string"fwd"
, and so it runs a third time. And so on, and so on.One way to exit the
while
loop when you want it to exit would be to set thedirection
variable to something else, like"stop"
, when you want to stop. (E.g., after you callmotor_stop()
). Another way would be to use thereturn
statement to exit the function at that point. But my suggestion would be to use thebreak
statement instead, which means "At this point, immediately exit the loop I'm in." It works on bothwhile
loops andfor
loops, and is a very useful statement to know about. It looks like you want yourwhile
loop to exit any time you callmotor_stop()
, so there are two places you'd put abreak
statement:There are a few other changes I'd suggest making. First, you call
get_range()
three times in your loop, but you really only need to call it once. You've already assigned its result to adist
variable, so why not use that variable?And second, there's no way inside the
while
loop fordirection
not to be "fwd", so the finalelse
is unnecessary, and your function can become:Finally, you have a function parameter named
arg
, which is a name that tells you nothing about what it's used for. You immediately assign it to a variable calleddirection
, which is a much better name. So why not use that as the parameter name in the first place? There's no rule that says a function's parameters must be called "arg"; they can be called anything you like (except one of Python's reserved words likebreak
orif
). So let's give your function a more meaningful parameter name, and that will simplify it even further:There. That's much easier to read and understand, and it should solve the problem you were seeing of your
while
loop not exiting when the car gets too close to an object.(There's still one possible problem I can see, which is that the while loop might not exit while the car is driving forward, even though you released the "forward" button -- but I'd have to see your
motor_forward()
code to know how to solve that one. It might be as simple as putting abreak
statement aftermotor_forward()
, in which case there would really be no need for awhile
loop at all -- but I'd have to know how yourmotor_forward()
code interacts with webiopi and how webiopi's event-handling code works. None of which I know right now, so I'm going to answer what problems I can answer now even if my answer is incomplete, rather than leave you with no answer at all.)Edit by Mark: Here is the motor_forward code: