Diddiborg with Ultraborg over Web UI
Forums:
Hi !
Need some help with my project.
I like to run the Diddiborg with Ultraborg over Web UI. I'm using the code I found on this Forum. https://www.piborg.org/node/1846
Two HC-SR04 are in the front of the Diddiborg. I get correct readings in the Web UI.
But when I try to use "Semi" or "Auto-mode" there is no reaction.
Another thing is to control LED lights over the Web UI but I'm not sure how to put inside. Right now I turn on the lights when I start the script and turn off when the script ends. >> # Settings Light
Thanks :-)
Andreas
- Log in to post comments


piborg
Sat, 01/23/2016 - 20:43
Permalink
Diddiborg with Ultraborg over Web UI
The reason that semi-automatic and automatic modes are not really working is that they are currently unfinished.
In its current state the automatic mode does nothing at all.
The semi-automatic mode should:
I do not remember if they have made any progress with the functionality since that version, but I think they were intending to make the automatic mode move around in a simlar fashion to the automaic carpet cleaners.
What you would need to do to make the LEDs do something entirely depends on what you want them to do.
For example if you were to change the values inside the various movement mode sections then they would show you which mode you are in.
e.g.
if movementMode == MANUAL_MODE: # User movement, wait a second before checking again GPIO.output(40, False) GPIO.output(38, False) GPIO.output(36, True) time.sleep(1.0)4ndr345
Sat, 01/23/2016 - 23:14
Permalink
Hi again !
Thanks for the hint to see which mode I'm in.
The semi-automatic mode doesn't work for me and I have no idea whats wrong.
Doesn't slow down and don't stop below 50 mm.
elif movementMode == SEMI_AUTO_MODE: # Semi-automatic movement mode, checks twice per second # Ultrasonic distance readings semi auto mode print 'Semi auto mode' GPIO.output(40, True) GPIO.output(38, False) GPIO.output(36, True) # Get the readings from ultra sensors print 'Reading distance' distance1 = int(UB.GetDistance1()) distance2 = int(UB.GetDistance2()) # Set critical allowed distance to object in front if distance1 <= 50: PBR.MotorsOff() elif distance1 <= 100: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft)4ndr345
Sun, 01/24/2016 - 00:09
Permalink
Finally I found the problem
Finally I found the problem with the semi-automatic mode.
Instead <=50 I have 150 and <=100 I have 300.
Diddiborg slow down and stop directly before the obstacle.
Web UI show 50 mm to obstacle...
elif movementMode == SEMI_AUTO_MODE: # Semi-automatic movement mode, checks twice per second # Ultrasonic distance readings semi auto mode print 'Semi auto mode' GPIO.output(40, True) GPIO.output(38, False) GPIO.output(36, True) # Get the readings from ultra sensors print 'Reading distance' distance1 = int(UB.GetDistance1()) distance2 = int(UB.GetDistance2()) # Set critical allowed distance to object in front if distance1 <= 150: PBR.MotorsOff() elif distance1 <= 300: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) # Set critical allowed distance to object in front if distance2 <= 150: PBR.MotorsOff() elif distance1 <= 300: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft)4ndr345
Sun, 01/24/2016 - 09:13
Permalink
Now I'm testing the Auto mode
Now I'm testing the Auto mode but having trouble getting the code free of buggs.
Need a little help to get ahead :-)
elif movementMode == AUTO_MODE: # Automatic movement mode, updates five times per second GPIO.output(40, False) GPIO.output(38, False) GPIO.output(36, False) # TODO: Fill in logic here # Get the readings from ultra sensors print 'Reading distance' distance1 = int(UB.GetDistance1()) distance2 = int(UB.GetDistance2()) if distance1 >= 150 and distance2 >= 150: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(driveLeft elif distance1 <= 149: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(-driveRight) PBR.SetMotor2(driveLeft) else distance2 <= 149: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft)piborg
Sun, 01/24/2016 - 15:09
Permalink
Semi and Auto mode logic
The distances shown in the web UI in that code are divided by 10, so they display as cm.
The values in the code are in mm, so they need to be 10 times larger.
e.g.
will be for distances below 15 cm as shown on the web UI.
The code you have shown for the auto mode has a couple of coding mistakes that will cause it to not work:
eliffor each additional condition,elseis only used to mean "anything that is not covered by anyiforelifabove".I guess you were trying to make him stop when too close.
You can simply the code a bit by only doing the
maxPowercalculation and the setting of the motors once.This is because each time you want to set the motors, the only difference is the speed you are setting.
I think something like this would do what you were intending:
elif movementMode == AUTO_MODE: # Automatic movement mode, updates five times per second GPIO.output(40, False) GPIO.output(38, False) GPIO.output(36, False) # TODO: Fill in logic here # Get the readings from ultra sensors print 'Reading distance' distance1 = int(UB.GetDistance1()) distance2 = int(UB.GetDistance2()) if distance1 >= 150 and distance2 >= 150: driveRight = 0.3 driveLeft = 0.3 elif distance1 <= 149: driveRight = 0.0 driveLeft = 0.0 elif distance2 <= 149: driveRight = 0.0 driveLeft = 0.0 PBR.SetMotor1(driveRight * maxPower) PBR.SetMotor2(-driveLeft * maxPower)4ndr345
Sun, 01/24/2016 - 16:00
Permalink
Thanks for your help.
Thanks for your help.
I will trying to make him turning left or right when too close.
When I run the script I get an error .
>> line 260
driveRight = 0.3
^
IndentationError: expected an indented block <<
4ndr345
Sun, 01/24/2016 - 17:40
Permalink
Here is my slightly working
Here is my slightly working update for the "Auto Mode"
In "Auto Mode" the Borg have to turn right when obstacle is detected. But it seems there is to much time between the Sono readings. The Borg turns around 45° degrees and don't see that the obstacle is still there.
Hoppe you can help me with this.
elif movementMode == AUTO_MODE: # Automatic movement mode, updates five times per second GPIO.output(40, False) GPIO.output(38, False) GPIO.output(36, False) # TODO: Fill in logic here # Get the readings from ultra sensors print 'Reading distance auto mode' distance1 = int(UB.GetDistance1()) distance2 = int(UB.GetDistance2()) if distance1 >= 350 or distance2 >= 350: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) elif distance1 <= 330 or distance2 <=330: driveRight = 0.5 * maxPower driveLeft = 0.5 * maxPower PBR.SetMotor1(-driveRight) PBR.SetMotor2(-driveLeft)piborg
Mon, 01/25/2016 - 12:53
Permalink
Fast ultrasonic updates
I think the reason the code is slow to react to changes is due to the onboard filtering performed by the UltraBorg.
UltraBorg has two modes for reading ditances:
Cleans up the distance readings to give better accuracy and stability.
The filtered readings update slowly, they may take up to 2 seconds to change to a new value.
Used by calling the
UB.GetDistanceX()functions.Provides the latest reading from the sensor without any filtering.
These raw readings update quickly, but they suffer from 'noise' and may be less accurate for measuring a fixed distance.
Used by calling the
UB.GetRawDistanceX()functions.I would suggest replacing
UB.GetDistance1()andUB.GetDistance2()withUB.GetRawDistance1()andUB.GetRawDistance2()and see if the response is faster.4ndr345
Mon, 01/25/2016 - 19:54
Permalink
Thanks again!
UB.GetRawDistanceX() works perfect; reading and response are much better.
Now I have to tune the setup for the moves. I will also try with one more ultrasonic module rear.
#!/usr/bin/env python # coding: Latin-1 # Creates a web-page interface for DiddyBorg Metal Edition # Import library functions we need import PicoBorgRev import time import sys import threading import SocketServer import picamera import picamera.array import cv2 import UltraBorg import datetime import RPi.GPIO as GPIO # Settings Light GPIO.setmode(GPIO.BOARD) GPIO.setup(40, GPIO.OUT) GPIO.setup(38, GPIO.OUT) GPIO.setup(36, GPIO.OUT) #GPIO.output(40, True) #GPIO.output(38, True) #GPIO.output(36, True) # Settings for the web-page webPort = 80 # Port number for the web-page, 80 is what web-pages normally use imageWidth = 480 # Width of the captured image in pixels imageHeight = 360 # Height of the captured image in pixels frameRate = 20 # Number of images to capture per second displayRate = 4 # Number of images to request per second photoDirectory = '/home/pi' # Directory to save photos to # Movement mode constants MANUAL_MODE = 0 # User controlled movement SEMI_AUTO_MODE = 1 # Semi-automatic movement AUTO_MODE = 2 # Fully automatic movement # Global values global PBR global lastFrame global lockFrame global camera global processor global running global watchdog global movementMode running = True movementMode = MANUAL_MODE # Setup the UltraBorg global UB UB = UltraBorg.UltraBorg() # Create a new UltraBorg object UB.Init() # Set the board up (checks the board is connected) # Setup the PicoBorg Reverse PBR = PicoBorgRev.PicoBorgRev() #PBR.i2cAddress = 0x44 # Uncomment and change the value if you have changed the board address PBR.Init() if not PBR.foundChip: boards = PicoBorgRev.ScanForPicoBorgReverse() if len(boards) == 0: print 'No PicoBorg Reverse found, check you are attached :)' else: print 'No PicoBorg Reverse at address %02X, but we did find boards:' % (PBR.i2cAddress) for board in boards: print ' %02X (%d)' % (board, board) print 'If you need to change the I²C address change the setup line so it is correct, e.g.' print 'PBR.i2cAddress = 0x%02X' % (boards[0]) sys.exit() #PBR.SetEpoIgnore(True) # Uncomment to disable EPO latch, needed if you do not have a switch / jumper PBR.SetCommsFailsafe(False) # Disable the communications failsafe PBR.ResetEpo() # Power settings voltageIn = 1.2 * 12 # Total battery voltage to the PicoBorg Reverse voltageOut = 12.0 # Maximum motor voltage # Setup the power limits if voltageOut > voltageIn: maxPower = 1.0 else: maxPower = voltageOut / float(voltageIn) # Timeout thread class Watchdog(threading.Thread): def __init__(self): super(Watchdog, self).__init__() self.event = threading.Event() self.terminated = False self.start() self.timestamp = time.time() def run(self): timedOut = True # This method runs in a separate thread while not self.terminated: # Wait for a network event to be flagged for up to one second if timedOut: if self.event.wait(1): # Connection print 'Reconnected...' timedOut = False self.event.clear() else: if self.event.wait(1): self.event.clear() else: # Timed out print 'Timed out...' timedOut = True PBR.MotorsOff() # Image stream processing thread class StreamProcessor(threading.Thread): def __init__(self): super(StreamProcessor, self).__init__() self.stream = picamera.array.PiRGBArray(camera) self.event = threading.Event() self.terminated = False self.start() self.begin = 0 def run(self): global lastFrame global lockFrame # This method runs in a separate thread while not self.terminated: # Wait for an image to be written to the stream if self.event.wait(1): try: # Read the image and save globally self.stream.seek(0) flippedArray = cv2.flip(self.stream.array, -1) # Flips X and Y retval, thisFrame = cv2.imencode('.jpg', flippedArray) del flippedArray lockFrame.acquire() lastFrame = thisFrame lockFrame.release() finally: # Reset the stream and event self.stream.seek(0) self.stream.truncate() self.event.clear() # Image capture thread class ImageCapture(threading.Thread): def __init__(self): super(ImageCapture, self).__init__() self.start() def run(self): global camera global processor print 'Start the stream using the video port' camera.capture_sequence(self.TriggerStream(), format='bgr', use_video_port=True) print 'Terminating camera processing...' processor.terminated = True processor.join() print 'Processing terminated.' # Stream delegation loop def TriggerStream(self): global running while running: if processor.event.is_set(): time.sleep(0.01) else: yield processor.stream processor.event.set() # Automatic movement thread class AutoMovement(threading.Thread): def __init__(self): super(AutoMovement, self).__init__() self.terminated = False self.start() def run(self): global movementMode # This method runs in a separate thread while not self.terminated: # See which mode we are in if movementMode == MANUAL_MODE: # User movement, wait a second before checking again #print 'Manual mode' GPIO.output(40, True) GPIO.output(38, True) GPIO.output(36, True) time.sleep(1.0) elif movementMode == SEMI_AUTO_MODE: # Semi-automatic movement mode, checks twice per second # Ultrasonic distance readings semi auto mode #print 'Semi auto mode' GPIO.output(40, True) GPIO.output(38, False) GPIO.output(36, True) # Get the readings from ultra sensors #print 'Reading distance' distance1 = int(UB.GetRawDistance1()) distance2 = int(UB.GetRawDistance2()) # Set critical allowed distance to object in front if distance1 <= 200: PBR.MotorsOff() elif distance1 <= 400: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) # Set critical allowed distance to object in front if distance2 <= 200: PBR.MotorsOff() elif distance2 <= 400: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) # Wait for 1/2 of a second before reading again time.sleep(0.1) elif movementMode == AUTO_MODE: # Automatic movement mode, updates five times per second GPIO.output(40, False) GPIO.output(38, False) GPIO.output(36, False) # Get the readings from ultra sensors distance1 = int(UB.GetRawDistance1()) distance2 = int(UB.GetRawDistance2()) #if distance1 >= 400 or distance2 >= 400: # driveRight = 0.4 * maxPower # driveLeft = 0.4 * maxPower # PBR.SetMotor1(driveRight) # PBR.SetMotor2(-driveLeft) if distance1 <= 350: driveRight = 0.5 * maxPower driveLeft = 0.5 * maxPower PBR.SetMotor1(-driveRight) PBR.SetMotor2(-driveLeft) elif distance2 <= 350: driveRight = 0.5 * maxPower driveLeft = 0.5 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(driveLeft) else: driveRight = 0.4 * maxPower driveLeft = 0.4 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) # Wait for 1/5 of a second before reading again time.sleep(0.0001) else: # Unexpected, print an error and wait a second before trying again print 'Unexpected movement mode %d' % (movementMode) time.sleep(0.01) # Class used to implement the web server class WebServer(SocketServer.BaseRequestHandler): def handle(self): global PBR global lastFrame global watchdog global movementMode # Get the HTTP request data reqData = self.request.recv(1024).strip() reqData = reqData.split('\n') # Get the URL requested getPath = '' for line in reqData: if line.startswith('GET'): parts = line.split(' ') getPath = parts[1] break watchdog.event.set() if getPath.startswith('/distances-once'): # Ultrasonic distance readings # Get the readings distance1 = int(UB.GetRawDistance1()) distance2 = int(UB.GetRawDistance2()) distance3 = int(UB.GetRawDistance3()) # Build a table for the values httpText = '' if distance1 == 0: httpText += 'None' else: httpText += '%04d' % (distance1/10) if distance3 == 0: httpText += 'None' else: httpText += '%04d' % (distance3/10) if distance2 == 0: httpText += 'None' else: httpText += '%04d' % (distance2/10) httpText += '' self.send(httpText) elif getPath.startswith('/semiAuto'): # Toggle Auto mode if movementMode == SEMI_AUTO_MODE: # We are in semi-auto mode, turn it off movementMode = MANUAL_MODE httpText = '' httpText += 'Speeds: 0 %, 0 %' httpText += '' self.send(httpText) PBR.MotorsOff() else: # We are not in semi-auto mode, turn it on movementMode = SEMI_AUTO_MODE httpText = '' httpText += 'Semi Mode' httpText += '' self.send(httpText) elif getPath.startswith('/Auto'): # Toggle Auto mode if movementMode == AUTO_MODE: # We are in auto mode, turn it off movementMode = MANUAL_MODE httpText = '' httpText += 'Speeds: 0 %, 0 %' httpText += '' self.send(httpText) PBR.MotorsOff() else: # We are not in auto mode, turn it on movementMode = AUTO_MODE httpText = '' httpText += 'Auto Mode' httpText += '' self.send(httpText) elif getPath.startswith('/cam.jpg'): # Camera snapshot lockFrame.acquire() sendFrame = lastFrame lockFrame.release() if sendFrame != None: self.send(sendFrame.tostring()) elif getPath.startswith('/off'): # Turn the drives off and switch to manual mode movementMode = MANUAL_MODE httpText = '' httpText += 'Speeds: 0 %, 0 %' httpText += '' self.send(httpText) PBR.MotorsOff() elif getPath.startswith('/set/'): # Motor power setting: /set/driveLeft/driveRight parts = getPath.split('/') # Get the power levels if len(parts) >= 4: try: driveLeft = float(parts[2]) driveRight = float(parts[3]) except: # Bad values driveRight = 0.0 driveLeft = 0.0 else: # Bad request driveRight = 0.0 driveLeft = 0.0 # Ensure settings are within limits if driveRight < -1: driveRight = -1 elif driveRight > 1: driveRight = 1 if driveLeft < -1: driveLeft = -1 elif driveLeft > 1: driveLeft = 1 # Report the current settings percentLeft = driveLeft * 100.0; percentRight = driveRight * 100.0; httpText = '' if movementMode == MANUAL_MODE: httpText += 'Speeds: %.0f %%, %.0f %%' % (percentLeft, percentRight) elif movementMode == SEMI_AUTO_MODE: httpText += 'Semi: %.0f %%, %.0f %%' % (percentLeft, percentRight) elif movementMode == AUTO_MODE: percentLeft = PBR.GetMotor2() * 100.0; percentRight = PBR.GetMotor1() * 100.0; httpText += 'Auto: %.0f %%, %.0f %%' % (percentLeft, percentRight) httpText += '' self.send(httpText) # Set the outputs as long as we are not in auto mode if movementMode != AUTO_MODE: driveLeft *= maxPower driveRight *= maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) elif getPath.startswith('/photo'): # Save camera photo lockFrame.acquire() captureFrame = lastFrame lockFrame.release() httpText = '' if captureFrame != None: photoName = '%s/Photo %s.jpg' % (photoDirectory, datetime.datetime.utcnow()) try: photoFile = open(photoName, 'wb') photoFile.write(captureFrame) photoFile.close() httpText += 'Photo saved to %s' % (photoName) except: httpText += 'Failed to take photo!' else: httpText += 'Failed to take photo!' httpText += '' self.send(httpText) elif getPath == '/': # Main page, click buttons to move and to stop httpText = '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += 'Spin Left\n' httpText += 'Forward\n' httpText += 'Spin Right\n' httpText += '\n' httpText += 'Turn Left\n' httpText += 'Stop\n' httpText += 'Turn Right\n' httpText += '\n' httpText += 'Semi Auto\n' httpText += 'Reverse\n' httpText += 'Auto Mode\n' httpText += '\n' httpText += 'Save Photo\n' httpText += '\n' httpText += '\n' httpText += 'Distances (cm)\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' self.send(httpText) elif getPath == '/stream': # Streaming frame, set a delayed refresh displayDelay = int(1000 / displayRate) httpText = '\n' httpText += '\n' httpText += '\n' httpText += '\n' httpText += '\n' % (displayDelay) httpText += '
\n'
httpText += '\n'
httpText += '\n'
self.send(httpText)
elif getPath == '/distances':
# Repeated reading of the ultrasonic distances, set a delayed refresh
# We use AJAX to avoid screen refreshes caused by refreshing a frame
displayDelay = int(1000 / displayRate)
httpText = '\n'
httpText += '\n'
httpText += 'Failed reading distances (not running?)";\n'
httpText += ' }\n'
httpText += ' }\n'
httpText += ' }\n'
httpText += ' xmlhttp.open("GET","distances-once",true);\n'
httpText += ' xmlhttp.send();\n'
httpText += ' setTimeout("readDistances()", %d);\n' % (displayDelay)
httpText += '}\n'
httpText += '//-->\n'
httpText += '\n'
httpText += '\n'
httpText += '\n' % (displayDelay)
httpText += 'Waiting for first distance reading...\n'
httpText += '\n'
httpText += '\n'
self.send(httpText)
else:
# Unexpected page
self.send('Path : "%s"' % (getPath))
def send(self, content):
self.request.sendall('HTTP/1.0 200 OK\n\n%s' % (content))
# Create the image buffer frame
lastFrame = None
lockFrame = threading.Lock()
# Startup sequence
print 'Setup camera'
camera = picamera.PiCamera()
camera.resolution = (imageWidth, imageHeight)
camera.framerate = frameRate
print 'Setup the stream processing thread'
processor = StreamProcessor()
print 'Wait ...'
time.sleep(2)
captureThread = ImageCapture()
print 'Setup the watchdog'
watchdog = Watchdog()
print 'Setup the automatic movement'
autoMovement = AutoMovement()
# Run the web server until we are told to close
httpServer = SocketServer.TCPServer(("0.0.0.0", webPort), WebServer)
try:
print 'Press CTRL+C to terminate the web-server'
while running:
httpServer.handle_request()
except KeyboardInterrupt:
# CTRL+C exit
print '\nUser shutdown'
finally:
# Turn the motors off under all scenarios
PBR.MotorsOff()
print 'Motors off'
# Tell each thread to stop, and wait for them to end
running = False
captureThread.join()
processor.terminated = True
watchdog.terminated = True
autoMovement.terminated = True
processor.join()
watchdog.join()
autoMovement.join()
del camera
PBR.SetLed(True)
GPIO.output(40, False)
GPIO.output(38, False)
GPIO.output(36, False)
print 'Web-server terminated.'
4ndr345
Tue, 01/26/2016 - 12:05
Permalink
Hello again ...
I wonder if I can read the direction?
When I'm in the "Semi" mode and the Borg stops I need to push the Stop button before I can move backwards. When "Semi" is on I can't drive backwards.
Like ...
Maybe end the "Semi mode"
if distance2 <= 200: PBR.MotorsOff() end == SEMI_AUTO_MODE elif distance2 <= 400: driveRight = 0.3 * maxPower driveLeft = 0.3 * maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft)piborg
Tue, 01/26/2016 - 12:43
Permalink
Checking direction
What you could do is make another couple of global variables for the users set speeds.
You can then do some simple tests to see what direction the DiddyBorg is set to move in.
Here are the basic bits to get a "direction" value which you can compare to presets:
# Add some new constants to the movement mode constants DIR_STOP = 0 DIR_FORWARD = 1 DIR_REVERSE = 2 DIR_LEFT = 3 DIR_RIGHT = 4 DIR_SPIN_LEFT = 5 DIR_SPIN_RIGHT = 6 DIR_REV_LEFT = 7 DIR_REV_RIGHT = 8 # Add these to the global section global userLeft global userRight userLeft = 0.0 userRight = 0.0 # Save the user set speeds in the "Motor power setting" section, above the AUTO_MODE check userLeft = driveLeft userRight = driveRight # This block can be run before your distance tests to determine the direction if (userLeft == 0.0): # Left stopped if (userRight == 0.0): # Both stopped direction = DIR_STOP elif (userRight > 0.0): # Turning left direction = DIR_LEFT else: # Reversing left direction = DIR_REV_LEFT elif (userLeft > 0.0): # Left forward if (userRight == 0.0): # Turning right direction = DIR_RIGHT elif (userRight > 0.0): # Both forward direction = DIR_FORWARD else: # Spinning right direction = DIR_SPIN_RIGHT else: # Left reverse if (userRight == 0.0): # Reversing right direction = DIR_REV_RIGHT elif (userRight > 0.0): # Spinning left direction = DIR_SPIN_LEFT else: # Both reverse direction = DIR_REVERSE4ndr345
Thu, 01/28/2016 - 17:08
Permalink
Thanks ...
I will try :-)
4ndr345
Thu, 02/04/2016 - 17:35
Permalink
Hello again !
The Raspberry Pi doesn’t have a power switch, which means I have to remember to properly shut it down every time I want to turn it off. So the idea is to add a Shutdown Switch to the Borg. The script alone runs fine but having trouble getting the code free of buggs when I try to put into the diddy script.
#!/usr/bin/env python # coding: Latin-1 import time import os import RPi.GPIO as GPIO #pins where the switch is connected buttonPin1 = 33 GPIO.setmode(GPIO.BCM) GPIO.setup(buttonPin1,GPIO.IN) while True: #assuming script1 if (GPIO.input(buttonPin1)): #this is the script that will be called (as root) os.system(”sudo shutdown-h now)piborg
Thu, 02/04/2016 - 17:58
Permalink
Power switch code
That is a good idea :)
It should be fairly easy to put that code into the diddyWeb.py script.
I think the simplest way would be to add these blocks of code:
At the bottom of the import list:
Before the "Timeout thread" code:
And add the highlighted lines to the section "Stream delegation loop" which is run each time an image is taken:
# Stream delegation loop def TriggerStream(self): global running global buttonPin1 while running: if processor.event.is_set(): time.sleep(0.01) else: yield processor.stream processor.event.set() # Check for button press if (GPIO.input(buttonPin1)): #this is the script that will be called (as root) os.system("sudo shutdown-h now")4ndr345
Thu, 02/04/2016 - 19:13
Permalink
Thanks :-)
Works fine, but I have to replace "sudo shutdown-h now" with "sudo init 0"
How to put in the code into the "metalJoy.py" script ?
piborg
Fri, 02/05/2016 - 11:40
Permalink
Adding code to metalJoy
Adding the button code to metalJoy.py is fairly simple:
# Loop indefinitely while running: # Check for button press if (GPIO.input(buttonPin1)): #this is the script that will be called (as root) os.system("sudo shutdown-h now") # Get the latest events from the system hadEvent = False events = pygame.event.get()4ndr345
Fri, 02/05/2016 - 20:05
Permalink
...
unfortunately it didn't work :-(
File "metaljoy.py", line 133
os.system("sudo shutdown-h now")
^
IndentationError: expected an indented block
piborg
Sun, 02/07/2016 - 00:44
Permalink
Python and indentation
That line needs to be further to the right than the
ifline above it.Put simply Python is sensitive to the use of tabs or spaces at the start of the line.
The error you are seeing is telling you it expected a line to start to the right of a line above.
cleric boomer
Wed, 02/10/2016 - 13:24
Permalink
Question about the switch
Hi PiBorg.
I am planning on having a power (battery power) switch, and also a button to switch off the pi.
The on/off switch is easy.
But the shut down switch using the code above, what sort of switch would that need to be?
push to break (momentary) or
push to make (momentary)?
Thanks in advance
Chris
piborg
Wed, 02/10/2016 - 13:53
Permalink
Shutdown switch
You could use either, but I would suggest a push to make would be best.
You should wire it with a weak pull-down resistor like this:

Use a nice large value like 10 KΩ for R1, Vcc will be the 3V3 pin.
cleric boomer
Tue, 03/29/2016 - 17:30
Permalink
Please forgive my ignorance
OK, I know I am going to sound stupid here..
But here goes.
Following on from your diagram, and also considering that the 6 pins are taken by the reverse board.
so cable to pin 17 - 3.3v
other end to switch.
2 wires attached to other side of switch.
one to pin 40 (GPIO 21)
other to pin 39 (Ground) via a low value resistor.
Then code which says when GPIO goes high run sudo shutdown now
does that sound right?
Cheers
Chris
piborg
Tue, 03/29/2016 - 17:40
Permalink
That's it
That is the basic idea, yes.
The only thing is that you want a large value resistor.
A larger value means less wasted power when the switch is on.
Too low and you might exceed the 50 mA maximum for the 3.3v pin.
For the resistor I would use at least 1 KΩ, which would use 3.3 mA when turned on.
Ideally something like 10 KΩ would be better, that would use 0.33 mA when turned on.
cleric boomer
Tue, 03/29/2016 - 17:55
Permalink
Thanks
10k resister.
I have some of those
4ndr345
Fri, 04/01/2016 - 17:48
Permalink
Turn on and off lights
Now I'm playing around with some ideas.
I try to turn on light over the Web UI. Unfortunately i have now luck.
To put the buttons on the Web UI was easy, but so easy to activate :-(
I was trying ...
elif getPath.startswith(’/Lighton'): # Lights on GPIO.output(38, True)But it won't work.
It will be very nice if you could lock at this. Thanks
# Class used to implement the web server class WebServer(SocketServer.BaseRequestHandler): def handle(self): global PBR global lastFrame global watchdog global movementMode # Get the HTTP request data reqData = self.request.recv(1024).strip() reqData = reqData.split('\n') # Get the URL requested getPath = '' for line in reqData: if line.startswith('GET'): parts = line.split(' ') getPath = parts[1] break watchdog.event.set() if getPath.startswith('/distances-once'): # Ultrasonic distance readings # Get the readings distance1 = int(UB.GetRawDistance1()) distance2 = int(UB.GetRawDistance2()) distance3 = int(UB.GetRawDistance3()) distance4 = int(UB.GetRawDistance4()) # Read and display time localtime = time.asctime( time.localtime(time.time()) ) # Build a table for the values httpText = '<html><body><center><table border="0" style="width:60%"><tr>' if distance1 == 0: httpText += '<td width="25%"><center>None</center></td>' else: httpText += '<td width="25%%"><center>Front: %04d</center></td>' % (distance4/10) if distance4 == 0: httpText += '<td width="25%"><center>None</center></td>' else: httpText += '<td width="25%%"><center>Left: %04d</center></td>' % (distance1/10) if distance3 == 0: httpText += '<td width="25%"><center>None</center></td>' else: httpText += '<td width="25%%"><center>Right: %04d</center></td>' % (distance2/10) if distance2 == 0: httpText += '<td width="25%"><center>None</center></td>' else: httpText += '<td width="25%%"><center>Rear: %04d</center></td>' % (distance3/10) httpText += '</tr></table>' httpText += 'Temperature: {0:0.1f}°C - Humidity: {1:0.1f}% '.format(temperature, humidity) #httpText += 'Wifi Signal Strength %.0f %%' % (wifiPercent) httpText += ' - %s' % (localtime) httpText += '</center></body></html>' self.send(httpText) elif getPath.startswith('/semiAuto'): # Toggle Auto mode if movementMode == SEMI_AUTO_MODE: # We are in semi-auto mode, turn it off movementMode = MANUAL_MODE httpText = '<html><body><center>' httpText += 'Speeds: 0 %, 0 %' httpText += '</center></body></html>' self.send(httpText) PBR.MotorsOff() else: # We are not in semi-auto mode, turn it on movementMode = SEMI_AUTO_MODE httpText = '<html><body><center>' httpText += 'Semi Mode' httpText += '</center></body></html>' self.send(httpText) elif getPath.startswith('/Auto'): # Toggle Auto mode if movementMode == AUTO_MODE: # We are in auto mode, turn it off movementMode = MANUAL_MODE httpText = '<html><body><center>' httpText += 'Speeds: 0 %, 0 %' httpText += '</center></body></html>' self.send(httpText) PBR.MotorsOff() else: # We are not in auto mode, turn it on movementMode = AUTO_MODE httpText = '<html><body><center>' httpText += 'Auto Mode' httpText += '</center></body></html>' self.send(httpText) elif getPath.startswith('/cam.jpg'): # Camera snapshot lockFrame.acquire() sendFrame = lastFrame lockFrame.release() if sendFrame != None: self.send(sendFrame.tostring()) elif getPath.startswith(’/Lighton'): # Lights on GPIO.output(38, True) elif getPath.startswith(’/Lightoff'): # Lights off GPIO.output(38, False) elif getPath.startswith('/off'): # Turn the drives off and switch to manual mode movementMode = MANUAL_MODE httpText = '<html><body><center>' httpText += 'Speeds: 0 %, 0 %' httpText += '</center></body></html>' self.send(httpText) PBR.MotorsOff() elif getPath.startswith('/set/'): # Motor power setting: /set/driveLeft/driveRight parts = getPath.split('/') # Get the power levels if len(parts) >= 4: try: driveLeft = float(parts[2]) driveRight = float(parts[3]) except: # Bad values driveRight = 0.0 driveLeft = 0.0 else: # Bad request driveRight = 0.0 driveLeft = 0.0 # Ensure settings are within limits if driveRight < -1: driveRight = -1 elif driveRight > 1: driveRight = 1 if driveLeft < -1: driveLeft = -1 elif driveLeft > 1: driveLeft = 1 # Report the current settings percentLeft = driveLeft * 100.0; percentRight = driveRight * 100.0; httpText = '<html><body><center>' if movementMode == MANUAL_MODE: httpText += 'Speeds: %.0f %%, %.0f %%' % (percentLeft, percentRight) elif movementMode == SEMI_AUTO_MODE: httpText += 'Semi: %.0f %%, %.0f %%' % (percentLeft, percentRight) elif movementMode == AUTO_MODE: percentLeft = PBR.GetMotor2() * 100.0; percentRight = PBR.GetMotor1() * 100.0; httpText += 'Auto: %.0f %%, %.0f %%' % (percentLeft, percentRight) httpText += '</center></body></html>' self.send(httpText) # Set the outputs as long as we are not in auto mode if movementMode != AUTO_MODE: driveLeft *= maxPower driveRight *= maxPower PBR.SetMotor1(driveRight) PBR.SetMotor2(-driveLeft) elif getPath.startswith('/photo'): # Save camera photo lockFrame.acquire() captureFrame = lastFrame lockFrame.release() httpText = '<html><body><center>' if captureFrame != None: photoName = '%s/Photo %s.jpg' % (photoDirectory, datetime.datetime.utcnow()) try: photoFile = open(photoName, 'wb') photoFile.write(captureFrame) photoFile.close() httpText += 'Photo saved to %s' % (photoName) except: httpText += 'Failed to take photo!' else: httpText += 'Failed to take photo!' httpText += '</center></body></html>' self.send(httpText) elif getPath == '/': # Main page, click buttons to move and to stop httpText = '<html>\n' httpText += '<head>\n' httpText += '<script language="JavaScript"><!--\n' httpText += 'function Drive(left, right) {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' var slider = document.getElementById("speed");\n' httpText += ' left *= speed.value / 100.0;' httpText += ' right *= speed.value / 100.0;' httpText += ' iframe.src = "/set/" + left + "/" + right;\n' httpText += '}\n' httpText += 'function Lightoff() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = ”/Lightoff";\n' httpText += '}\n' httpText += 'function Lighton() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = ”/Lighton;\n’ httpText += '}\n' httpText += 'function Off() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = "/off";\n' httpText += '}\n' httpText += 'function Photo() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = "/photo";\n' httpText += '}\n' httpText += 'function semiAuto() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = "/semiAuto";\n' httpText += '}\n' httpText += 'function Auto() {\n' httpText += ' var iframe = document.getElementById("setDrive");\n' httpText += ' iframe.src = "/Auto";\n' httpText += '}\n' httpText += '//--></script>\n' httpText += '</head>\n' httpText += '<body>\n' httpText += '<iframe src="/stream" width="100%" height="500" frameborder="0"></iframe>\n' httpText += '<iframe id="setDrive" src="/off" width="100%" height="50" frameborder="0"></iframe>\n' httpText += '<center>\n' httpText += '<button onclick="Drive(-1,1)" style="width:200px;height:40px;"><b>Spin Left</b></button>\n' httpText += '<button onclick="Drive(1,1)" style="width:200px;height:40px;"><b>Forward</b></button>\n' httpText += '<button onclick="Drive(1,-1)" style="width:200px;height:40px;"><b>Spin Right</b></button>\n' httpText += '<br /><br />\n' httpText += '<button onclick="Drive(0,1)" style="width:200px;height:40px;"><b>Turn Left</b></button>\n' httpText += '<button onclick="Off()" style="width:200px;height:40px;"><b>Stop</b></button>\n' httpText += '<button onclick="Drive(1,0)" style="width:200px;height:40px;"><b>Turn Right</b></button>\n' httpText += '<br /><br />\n' httpText += '<button onclick="semiAuto(1)" style="width:200px;height:40px;"><b>Semi Auto</b></button>\n' httpText += '<button onclick="Drive(-1,-1)" style="width:200px;height:40px;"><b>Reverse</b></button>\n' httpText += '<button onclick="Auto(1)" style="width:200px;height:40px;"><b>Auto Mode</b></button>\n' httpText += '<br /><br />\n' httpText += '<button onclick=”Lighton()” style="width:200px;height:40px;"><b>Light On</b></button>\n' httpText += '<button onclick="Photo()" style="width:200px;height:40px;"><b>Save Photo</b></button>\n' httpText += '<button onclick=”Lightoff()” style="width:200px;height:40px;"><b>Light Off</b></button>\n' httpText += '<br /><br />\n' httpText += '<input id="speed" type="range" min="0" max="100" value="40" style="width:600px" />\n' httpText += '<br /><center> - Distances - </centre><br />\n' httpText += '<iframe src="/distances" width="100%" height="200" frameborder="0"></iframe>\n' httpText += '</center>\n' httpText += '</body>\n' httpText += '</html>\n' self.send(httpText)piborg
Sat, 04/02/2016 - 09:58
Permalink
Turn on and off lights
This might be a problem cause by your text editor :)
Programming languages are very picky about the character symbols used in code.
In particular the quoting marks for Python and HTML need to be of the
"or'type.At the moment you have:
httpText += ' iframe.src = ”/Lightoff";\n'and
httpText += ' iframe.src = ”/Lighton;\n’for example which look like the text editor has swapped some of the quotes and double-quotes with the fancier style ones.
What you wanted to have was:
httpText += ' iframe.src = "/Lightoff";\n'and
httpText += ' iframe.src = "/Lighton";\n'The symbols you want to use are:
" 'The ones you want to watch out for are:
“ ‟ ‘ ‛These are often used by editors such as Word to make you text look nicer.
There are a fair number of lines with these rouge symbols, and they can be quite hard to spot.
I would suggest either using the find tool on your editor if it has one, otherwise turning the font size up helps a lot.
In the section of code you posted there appear to be bad quote symbols on lines: 101, 105, 200, 204, 240, 242.
4ndr345
Sat, 04/02/2016 - 17:40
Permalink
Thanks so much :-)
Thanks so much :-)
These “ ‟ ‘ ‛ characters was killing all, now it works perfect.