1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | # coding=latin-1 # # File: scribpro.py # by Justin Mangue # # Description: # This is a script that enables use of a Prolog natural language parsing component to control a Scribbler II robot # over bluetooth. Use in sync with nlp.pl. # # Dependencies: # Python 2.7.4 http://www.python.org/getit/ # PySwip 0.2.3 https://code.google.com/p/pyswip/ # PySpeech https://code.google.com/p/pyspeech/ # Myro 2.9.5 http://myro.roboteducation.org/download/ # Swi-Prolog 6.2.6 http://www.swi-prolog.org/Download.html # IMPORTS from sys import exit from myro import * from pyswip import Prolog import speech as pyspeech # GLOBAL SETTINGS verNum = '0.6' # ScribPro Version Number scribblerPort = 'COM5' # Scribbler Bluetooth Port prologFile = 'nlp.pl' # Prolog file to consult debug = 'on' # Debug mode, if enabled, shows detailed prolog parse information inputMode = "text" # Input in text mode by default outputMode = "text" # Output to text by default # CLASSES class PrologResult( object ): def __init__( self , prologcall, status, pythoncode): self .prologcall = prologcall self .status = status self .pythoncode = pythoncode # FUNCTIONS def strClean(string): """ strClean(str) -- converts "A string like This" into a list of lowercase atoms i.e. [a,string,like,this] for use in Prolog. also converts commas to "and"s """ finalstring = "[" loweredstring = string.lower() exclude = '!"#$%&' () * + - . / :;< = >?@[\]^_`{|}~' for c in exclude: loweredstring = loweredstring.replace(c,"") for ch in loweredstring: if ch = = ' ' : finalstring = finalstring + "," elif ch = = ',' : finalstring = finalstring + ",comma" #elif ch == u'xb0' or ch == '°': # finalstring = finalstring + ",degrees" else : finalstring = finalstring + ch return finalstring + "]" def parse(inStr): """parse(str) -- cleans the user input and then throws it at Prolog for analysis""" codeOut = "null" sentence = strClean(inStr) prologCall = 'parseToCode(' + sentence + ', Status, CodeOut).' for soln in prolog.query(prologCall, maxresult = 1 ): statusOut = ''.join(soln[ "Status" ]) if statusOut = = 'valid' : codeOut = buildMultiCode(soln[ "CodeOut" ]) return PrologResult(prologCall,statusOut,codeOut) def buildCode(prologterms): """converts a [instruction, param1, param2, ...] list into Python-exec-friendly "instruction(param1,param2,...)" functor format""" parameters = [ str (item) for item in prologterms] if len (parameters) > 2 : codeOut = parameters[ 0 ] + '(' for x in range ( len (parameters) - 2 ): codeOut = codeOut + parameters[x + 1 ] + ', ' codeOut = codeOut + parameters[ len (parameters) - 1 ] + ')' elif len (parameters) = = 2 : codeOut = parameters[ 0 ] + '(' + parameters[ 1 ] + ')' else : codeOut = parameters[ 0 ] + '()' return codeOut def buildMultiCode(instructions): """converts a list of [instruction, param1, param2] codes into a list of Python-exec-friendly "instruction(param1,param2,...)" strings i.e. buildMultiCode([('forward',['1.0','3.0']),('stop',[])]) -> ['forward(1.0, 3.0)', 'stop()']""" multiCodeOut = [] for x in instructions: line = buildCode(x) multiCodeOut.append(line) return multiCodeOut def execute(code): # potential security concerns here! """executes multiple lines of python script in sequence""" for line in code: if type (line) is list : execute(line) else : exec line def toggle_inputMode(mode): """toggles between text and voice mode""" if mode = = "text" : print "Now activating voice input." return "voice" else : print "Switching back to text-input mode." return "text" def toggle_outputMode(mode): """toggles between text and voice mode""" if mode = = "text" : print "Now activating voice output." return "voice" else : print "Switching back to text-only output mode." return "text" def toggle_debugMode(): """toggles between debug mode being on/off""" if debug = = "on" : print "Disabling debug mode." return "off" else : print "Enabling debug mode." return "on" # addon robot commands def takePhoto(mode): """Take and display a photo in the specified color mode. 2=color(fast), 1=color, 0=gray""" if mode = = 2 : pic = takePicture( "jpeg-fast" ) elif mode = = 1 : pic = takePicture( "color" ) else : pic = takePicture( "gray" ) show(pic, "Scribby Cam" ) return def move_until_wall(): """Repeatedly moves forward in small increments until wall is sensed""" while not wall(): forward( 1.0 , 0.7 ) return def moonwalk(time): """Moonwalk backwards for time""" while timeRemaining(time): forward(. 25 ,. 1 ) backward( 1 ,. 3 ) # MAIN def main(): # global variable references global debug global prolog global inputMode global outputMode # initialize the robot print "***************** ScribPro v" + verNum + " *****************" init(scribblerPort) print "Scribbler II found on bluetooth (" + scribblerPort + ")." # instantiation of Prolog interface prolog = Prolog() prolog.consult(prologFile) print "Prolog has been initialized." print "Loaded " + prologFile + " into SWI-Prolog!" print "Starting in " + inputMode + " input mode. ['voice' to toggle]" print "Starting in " + outputMode + " output mode. ['sound' to toggle]" print "*************************************************" # main routine while ( 1 ): # grab a line of input, either text or voice if inputMode = = "voice" : try : inStr = pyspeech. input ( "nAwaiting voice command. (Ctrl-C to enter text)" ) print "Voice command: " + inStr + "n" except KeyboardInterrupt: inStr = raw_input ( "Type in a command: " ) else : inStr = raw_input ( "nEnter a command: " ) # parse the input and behave appropriately if (inStr = = 'quit' or inStr = = 'exit' ): print "Exiting..." exit( 0 ) elif inStr = = 'reload' : newprolog = Prolog() newprolog.consult(prologFile) prolog = newprolog print "Reloaded " + prologFile + " into Prolog!" elif inStr = = 'voice' : inputMode = toggle_inputMode(inputMode) elif inStr = = 'sound' : outputMode = toggle_outputMode(outputMode) elif inStr = = 'debug' : debug = toggle_debugMode() else : Result = parse(inStr) if Result.status = = 'valid' : if outputMode = = "voice" : pyspeech.say( "Okay" ) print "Okay." execute(Result.pythoncode) else : if outputMode = = "voice" : errorMsg = "I don't understand " + inStr pyspeech.say(errorMsg) print "I don't understand " " + inStr + " "." # Print detailed debug information if debug = = "on" : print "nProlog query executed:" , Result.prologcall print "Status:" , Result.status print "CodeOut:" , Result.pythoncode if __name__ = = "__main__" : main() |