\documentclass[a4paper, 12pt]{article} %\usepackage{savetrees} \usepackage{graphicx} \usepackage{subfig} %code for creating python code snippets \usepackage{float} \floatstyle{ruled} \newfloat{python}{H}{lop} \floatname{python}{Listing} %end code for creating python code snippets \usepackage{verbatim} \usepackage{moreverb} \graphicspath{{./images/}} \title {Student Robotics 2009\\ Programming Reference V2} \date{\today} \setcounter{tocdepth}{1} \begin{document} \maketitle \noindent This document details the programming interface for Student Robotics robots. {\bf This is not intended to be an introduction to the Python programming language.} For more information on programming in Python and about how to bring all this together see the tutorials linked to from the website. \section{Directory structure} The minimum requirement to create a functioning program using the IDE, is to have a python file called \texttt{robot.py} in a `project' . Exporting your project from the IDE will generate a zip file containing your code packaged as a python module. This file can be saved to your memory stick and inserted into your robot. To make your program easier to read and maintain you can split you code across multiple files within a project. The export function of the IDE will package the zip file correctly. \subsection{robot.py} This file must at least contain the main function for the robot control algorithm - see Listing \ref{py:main}: \begin{python} \begin{verbatimtab} def main( game, colour ): #Where game is either GOLF or SQUIRREL #colour is one of RED, BLUE, GREEN or YELLOW \end{verbatimtab} \caption{\label{py:main}Minimum contents of robot.py} \end{python} \subsection{import} Before you can control any of the student robotic kit e.g. motors, servos etc. you need to tell python to \textit{import} the Student Robotics interface (functions specific to the SR kit). Listing \ref{py:import} should appear at the top \begin{python} \begin{verbatimtab} #Import the Student Robotics Interface from sr import * #rest of code follows... \end{verbatimtab} \caption{\label{py:import}} \end{python} \section{Main function} The function \texttt{main} in \texttt{robot.py} is the first part of your code to be executed. It makes the following two variables available to your code: \begin{description} \item[game] The type of competition round being played i.e. Squirrel or Golf \item[colour]The colour of \textit{your team's} balls. \end{description} This information is sent wirelessly to your robot at the start of each round. The game types are available as constants for use in your code, as in Listing \ref{py:gametype}. \begin{python} \begin{verbatimtab} from sr import * def main( game, colour ): #Where game is either GOLF or SQUIRREL #colour is one of the colour constants from above if game == GOLF: print "Playing Golf Game..." yield run_golf #function defined elsewhere elif game == SQUIRREL: print "Playing Squirrel Game..." yield run_squirrel #function defined elsewhere \end{verbatimtab} \caption{\label{py:gametype}} \end{python} Similarly the colour constants: \texttt{RED, BLUE, YELLOW, GREEN} will be available for use with the vision methods. \section{Yielding control and interrupts} Once the main function is called, the algorithm has control of the robot. The algorithm must \texttt{yield} control of the robot once it has processed any incoming data, and configured any outputs accordingly. The \texttt{yield} command passes control of the robot over to the Student Robotics environment. When an event occurs, the environment will pass control back to the algorithm at the instruction after the \texttt{yield} statement. When control is passed back to the algorithm the \texttt{event} variable has been set to contain information about the event that just occurred. \subsection{Timeouts} The \texttt{yield} statement can be used to wait for a set amount of time. For example: \begin{verbatimtab} yield 3.4 \end{verbatimtab} Causes the program to be delayed for 3.4 seconds. \subsection{Waiting on IO events} The \texttt{yield} statement can be used to wait for an event to occur. For example: \begin{verbatimtab} yield io.pin[0] \end{verbatimtab} Causes the algorithm to wait until pin 0 changes on the JointIO board. If you are only interested in certain inputs or conditions, then you can specify this in the yield statement: \begin{python} \begin{verbatimtab} # Wait for input 3 to change digital value yield io.pin[3] # Wait for input 3 to become digital '1' (threshold 512) yield io.pin[3] == 1 # Wait for input 2 readings to exceed 1V yield io.apin[2] > 1 # Wait for input 2 readings to go below 2.5V yield io.apin[2] < 2.5 \end{verbatimtab} \caption{\label{py:yieldio}Yielding on specified pin inputs} \end{python} \subsection{Yielding on Power Board Events} The power board has a bank of four switches which you can yield on: \begin{verbatim} yield power.switch[x] == 0 \end{verbatim} Where \texttt{x} can take the values: \{0, 1, 2, 3\}. \subsection{Yielding on Vision Events} The following command will cause a new image to be captured by the webcam and processed by the slug. Your algorithm will resume when the image has been processed and all the blobs of colours have been extracted from it. \begin{verbatimtab} yield vision() \end{verbatimtab} \subsection{Combinations of events and timeout} The \texttt{yield} statement can be used to wait on a combination of events and a timeout, whichever occurs first: \begin{verbatimtab} yield io.pin[0], 5 \end{verbatimtab} Causes the algorithm to wait until a digital IO event is received or 5 seconds, whichever comes first. \subsection{Logic Expressions} Sometimes you may want to wait for event A to occur AND event B to occur before proceeding. This can be achieved using the `\&' symbol (Logical AND operator) or the And() function: \begin{python} \begin{verbatim} #wait for input pin 3 to be logic 1 and input pin 2 to be logic 0 yield (io.pin[3] == 1) & (io.pin[2] == 0) #wait for pins 1 and 3 to change, and for pin 2 to be logic 1 yield And(io.pin[1], io.pin[2] == 1, io.pin[3]) \end{verbatim} \caption{\label{py:yieldand}Yielding on multiple events using logical AND} \end{python} The \texttt{And()} function can take an unlimited (within reason) number of events. It is functionally equivalent, but can be syntactically easier to read than `\&' operator. \vspace{12pt} A logical OR operation can be used to wait for any one of a list of events to occur. It is implemented using the `\texttt{|}' operator or the Or() function: \begin{python} \begin{verbatim} #wait for pin 1 to change or pin 3 to go above 2V: yield io.pin[1] | (io.apin[3] >2) #wait for pin 1 or pin 2 or pin 3 to change: yield Or(io.pin[1], io.pin[2], io.pin[3]) \end{verbatim} \caption{\label{py:yieldor}Yielding on multiple events using logical OR} \end{python} \noindent\textbf{Note:} Any of the event types discussed above can be used in combination with these logical operators. \subsection{Calling subroutines} Control of the robot can be passed to subroutines, allowing the program to be split up into easier to understand parts. The \texttt{yield} statement can be used to pass control of the robot to a subroutine. When the subroutine returns, the program continues from the yield statement. If more information is passed to yield after the name of a subroutine, then that information is passed as argument(s) to that subroutine. For example: \begin{verbatimtab} yield findTokens, 3 \end{verbatimtab} Causes control of the robot to be passed to the findTokens subroutine with the argument 3. \section{Events} \subsection{The \texttt{event} variable} The \texttt{event} variable is set when control is returned after a yield. It contains information regarding the event that caused control to be passed back. It is often necessary to know which type of event has occurred and some further details about the event. \vspace{12pt} The \texttt{event} variable will return true when compared to the event source that led to its creation: \begin{python} \begin{verbatimtab} yield ... if event == io: pass #A io event happened first (pass means do-nothing) elif event == timeout: pass #A timeout event happened first elif event == vision: pass #A vision event happened first elif event == power_switch: pass #A power switch event happened first \end{verbatimtab} \caption{\label{py:events} Student Robotics event types} \end{python} \texttt{ io, timeout, vision} \& \texttt{power\_switch} are provided as global types which you can directly access from your robot code. \subsection{IO Events} IO events are caused by a change in the digital inputs of the Joint IO board. After a io event causes a \texttt{yield} statement to return control of the robot to the control algorithm, the \texttt{event} variable will be set. The io inputs that have changed are contained in a dictionary that can be accessed from \texttt{event.pins}: \begin{verbatimtab} yield io.apin[1] > 1.6, (io.pin[2] == 1) & (io.pin[3] == 0) if 2 in event.io.pins: # event.io.vals is an array of the pin values # e.g. event.io.vals[2] gives the value of the pin when the event happened # the value of event.io.vals[0] is meaningless # (and may later throw an error if read at the wrong time) elif 1 in event.io.pins: # event.io.vals[1] is a voltage (float) \end{verbatimtab} \subsection{Visual Events} When the \texttt{vision} event source is passed to the \texttt{yield} command, the robot will grab an image with its webcam and start to process that image. When this processing has finished, the vision system will raise an event (whether a token is seen or not). Any tokens found are placed in the list \texttt{event.vision.blobs}. Each blob in this list has a set of properties: \begin{description} \item[blob.x] The centre x coordinate of the blob (measured from left) \item[blob.y] The centre y coordinate of the blob (measured from top) \item[blob.mass] The number of pixels that make up the blob \item[blob.colour] The colour of the blob (RED, BLUE, YELLOW, GREEN) \item[blob.height] The height in pixels of the blob \item[blob.width] The width in pixels of the blob \end{description} To aid with processing the list of blobs, the following constants are provided: \begin{description} \item[VISION\_HEIGHT] The height in pixels of the raw jpg image \item[VISION\_WIDTH] The width in pixels of the raw jpg image \end{description} \begin{python} \begin{verbatimtab} yield vision() #This will always return as soon as #a frame has been processed if event == vision: for blob in event.vision.blobs: #Iterate blob list if not blob.colour == colour: #Ignore Opponents pass #blobs. else: #If one of ours, pickUpBlob() #pick it up! break #break out of loop \end{verbatimtab} \caption{\label{py:vision}Example of the vision event and its event properties} \end{python} \section{Controlling the robot} \subsection{Controlling the motors} The motor controller has two outputs. The \texttt{setpower} command sets the direction of each motor and the power delivered to each one. \begin{description} \item[setpower(n)] This sets both of the motors to n\% of maximum power. $-100 3.1), 4 #check ball detector# if event == io: setpos(0, 100) #sweep ball into robot yield 2 setpos(0, 0) return \end{verbatimtab} \caption{\label{list:noco} Without coroutines} \end{python} Now consider Listing \ref{list:co}. navigate() and collect() have been made coroutines by decorating them with @coroutine: \begin{verbatimtab} @coroutine def function_name(): \end{verbatimtab} This tells the robot to run navigate() and collect() and main() simultaneously! This is possible because whenever a yield statement occurs within a coroutine function, control of the robot is handed over to the next coroutine. This ensures that each coroutine gets a chance to be executed. If for example you add the following coroutine: \begin{verbatimtab} @coroutine def block(): while True: pass \end{verbatimtab} which never yields, then none of the other coroutines will ever execute and your robot will be stuck in this while loop. When a coroutine returns it will not restart. If you want a coroutine to run forever, you must add a while True loop. \begin{python} \begin{verbatimtab} from sr import * def main(game, colour): while True: #flash an led on the power board setled(0,1) yield 5 setled(0, 0) yield 5 @coroutine def navigate(): while True: setpower(100, 100) yield io.pin[0], 2 if event == io and 0 in event.io.pins: #check front bump sensor setpower(-10,-100) #turn around yield 3 setpower(100, 100) @coroutine def collect(): while True: yield (io.apin[3] > 1.3), 4 #check ball detector# if event == io: setpos(0, 100) #sweep ball into robot yield 2 setpos(0, 0) \end{verbatimtab} \caption{\label{list:co} With coroutines} \end{python} Listing \ref{list:co} simultaneously monitors and reacts to a bump switch and the ball detector. The number of coroutines you can add is unlimited but, be sure to add a least one yield statement in each. Finally, you do not have to have all of your coroutines starting at the same time as main(). Instead you can use the following function to add them when necessary. NOTE: function\_name should be typed without the `()'s. \begin{verbatimtab} add_coroutine(function_name) \end{verbatimtab} \end{document} % LocalWords: IDE