Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
doc:beginner:process_modules [2014/10/21 12:31] – Continued work on the "Writing a process module for the turtlesim" section. mpomarlan | doc:beginner:process_modules [2015/05/11 17:01] (current) – removed gkazhoya | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Creating process modules ====== | ||
- | |||
- | **Description: | ||
- | |||
- | **Previous Tutorial:** [[doc: | ||
- | **Next Tutorial: | ||
- | |||
- | ===== Process modules: an overview ===== | ||
- | |||
- | A process module is a program that controls a robot actuator. Different robots will have different kinds of actuators, requiring different kinds of controllers, | ||
- | |||
- | For better organization, | ||
- | |||
- | * :navigation | ||
- | * :ptu | ||
- | * : | ||
- | * :perception | ||
- | |||
- | A plan will typically refer to a process module by the alias. The process module would be defined for the particular robot in use and associated with the proper alias when the system is initialized. | ||
- | |||
- | Here's an example of invoking a process module: | ||
- | |||
- | <code lisp> | ||
- | (with-designators ((my-designator (location ' | ||
- | (pm-execute :navigation my-designator)) | ||
- | </ | ||
- | |||
- | This will run a process module associated to :navigation and use my-designator to pass parameters to it. In this case, the designator is a semantic description of a target location and it's up to the process module to ask that this designator be resolved (by some appropriate other module in the system) so as to get an actual location and then control the robot to reach the target. The specifics of the controller may vary enormously; the robot might be differential drive, or legged. But these details are not important for this high level plan. All we want is for the robot to approach the fridge, in whatever way it can carry itself there. | ||
- | |||
- | ===== Writing a process module for the turtlesim ===== | ||
- | |||
- | Once again, some new dependencies must be declared in the tutorial files you've been working on. | ||
- | |||
- | In your package.xml file you need to add build and runtime dependencies on actionlib_lisp, | ||
- | |||
- | < | ||
- | < | ||
- | < | ||
- | < | ||
- | |||
- | < | ||
- | < | ||
- | < | ||
- | </ | ||
- | |||
- | Similarly, in your .asd file you should add cram-language-designator-support, | ||
- | |||
- | <code lisp> | ||
- | (defsystem cram-beginner-tutorial-workthrough | ||
- | :depends-on (roslisp cram-language turtlesim-msg cl-transforms geometry_msgs-msg designators cram-reasoning | ||
- | | ||
- | :components | ||
- | ((:module " | ||
- | :components | ||
- | ((:file " | ||
- | | ||
- | </ | ||
- | |||
- | ==== A process module for the turtlesim ==== | ||
- | |||
- | We first need to connect to the turtlesim as a client for an action that will have the turtle draw a shape. To do this, append the following to your tutorial.lisp file | ||
- | |||
- | <code lisp> | ||
- | (defvar *navp-client* nil) | ||
- | |||
- | (defun init-action-client () | ||
- | (setf *navp-client* (actionlib: | ||
- | " | ||
- | " | ||
- | (roslisp: | ||
- | " | ||
- | ;; workaround for race condition in actionlib wait-for server | ||
- | (loop until | ||
- | (actionlib: | ||
- | (roslisp: | ||
- | " | ||
- | |||
- | (defun get-action-client () | ||
- | (when (null *navp-client*) | ||
- | (init-action-client)) | ||
- | *navp-client*) | ||
- | </ | ||
- | |||
- | The above code simply declares a variable *navp-client* which we can then initialize with a pointer to our ROS action client and retrieve this pointer later with the init-action-client and get-action-client functions, respectively. | ||
- | |||
- | We'll need a way to tell the action client to move along a shape (which is specified by a number of edges and a radius), so append this to tutorial.lisp: | ||
- | |||
- | <code lisp> | ||
- | (defun make-shape-action-goal (in-edges in-radius) | ||
- | (actionlib: | ||
- | edges in-edges | ||
- | radius in-radius)) | ||
- | |||
- | (defun call-shape-action (&key edges radius) | ||
- | (multiple-value-bind (result status) | ||
- | (with-failure-handling | ||
- | ((simple-error (e) | ||
- | | ||
- | (setf *navp-client* nil) | ||
- | | ||
- | (let ((actionlib: | ||
- | (actionlib: | ||
- | | ||
- | | ||
- | (roslisp: | ||
- | (values result status))) | ||
- | </ | ||
- | |||
- | In the above code we define a simple function to convert an edge and radius pair of values into a goal for the action client, and a function that will call said action client, with some error handling built in (for example, if the function is called without an action client being defined, it will (re)initialize one and retry). | ||
- | |||
- | Now that the lower level of controlling the turtlesim is taken care of, it's finally time to look at process modules and their interface to the higher levels. Append the following to tutorial.lisp: | ||
- | |||
- | <code lisp> | ||
- | (cram-process-modules: | ||
- | (roslisp: | ||
- | " | ||
- | action-designator) | ||
- | (destructuring-bind (cmd action-goal) (reference action-designator) | ||
- | (ecase cmd | ||
- | (shape | ||
- | | ||
- | :edges (turtle-shape-edges action-goal) | ||
- | :radius (turtle-shape-radius action-goal)))))) | ||
- | |||
- | |||
- | (defmacro with-turtle-process-modules (&body body) | ||
- | `(cpm: | ||
- | | ||
- | , | ||
- | </ | ||
- | |||
- | First, we use the cram-process-modules: | ||
- | |||
- | destructuring-bind will map the results from (reference action-designator) to the variables cmd and action-goal respectively. Note that the inference rules we defined previously provide a name for the kind of action goal we have (currently, all are " | ||
- | |||
- | The with-turtle-process-modules macro is a macro we define for convenience. It allows us to set up a context in which to run commands, knowing that the turtle process modules are all running concurrently. Right now we only have one defined, turtle-actuators. When we will have several, we will add them to the list we pass to cpm: | ||
- | |||
- | Let's try this out. Make sure you have roscore, turtlesim, and turtle_actionlib running. In a terminal tab for each, | ||
- | |||
- | < | ||
- | $ roscore | ||
- | $ rosrun turtlesim turtlesim_node | ||
- | $ rosrun turtle_actionlib shape_server | ||
- | </ | ||
- | |||
- | (**Note** on Oct. 21st 2014: you should check out then catkin_make the ROS common_tutorials from github to make sure you have the newest turtle_actionlib version available, otherwise the turtle might not move. To clone the ros_common tutorials, you will need to | ||
- | |||
- | < | ||
- | git clone https:// | ||
- | </ | ||
- | |||
- | inside the src folder of a ROS workspace, then catkin_make it.) | ||
- | |||
- | For convenience, | ||
- | |||
- | <code lisp> | ||
- | (defun start-tutorial () | ||
- | (let ((turtle-name " | ||
- | (start-ros-node turtle-name) | ||
- | (init-ros-turtle turtle-name) | ||
- | (top-level | ||
- | (with-turtle-process-modules | ||
- | (cpm: | ||
- | (cram-language-designator-support: | ||
- | ((trajectory (action ' | ||
- | (loc (location ' | ||
- | (cpm: | ||
- | </ | ||
- | |||
- | What the function does is simply start a ROS node for our turtle and sets up the action client, then activates the turtle process modules (in our case, the sole existing one), creates a designator to describe how the turtle should move, and calls the cpm: | ||
- | |||
- | Two other things to observe here are the use of the top-level macro, which sets up a CRAM running context and is needed for with-turtle-process-modules. Also, we declare that : | ||
- | |||
- | Reload the tutorial in REPL, and let's try to start the tutorial | ||
- | |||
- | <code lisp> | ||
- | TUT> (start-tutorial) | ||
- | [(ROSLISP TOP) INFO] 1413894471.489: | ||
- | [(ROSLISP TOP) INFO] 1413894471.489: | ||
- | [(ROSLISP TOP) INFO] 1413894471.489: | ||
- | [(ROSLISP TOP) INFO] 1413894471.489: | ||
- | [(ROSLISP TOP) INFO] 1413894471.489: | ||
- | [(ROSLISP TOP) INFO] 1413894472.493: | ||
- | [(TURTLE-PROCESS-MODULES) INFO] 1413894472.501: | ||
- | SHAPE) | ||
- | | ||
- | HEXAGON) | ||
- | | ||
- | 3)) {10084BC463}>' | ||
- | An error occured! | ||
- | Client lost connection to server. | ||
- | Reinitializing... | ||
- | |||
- | [(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1413894480.479: | ||
- | [(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1413894482.480: | ||
- | [(TURTLE-SHAPE-ACTION-CLIENT) INFO] 1413894505.711: | ||
- | [TURTLE_ACTIONLIB-MSG: | ||
- | | ||
- | | ||
- | | ||
- | | ||
- | :SUCCEEDED | ||
- | </ | ||
- | |||
- | You should also see the turtle move in the turtlesim window and trace the required trajectory. | ||
- | |||
- | == Next == | ||
- | |||
- | //to be defined// | ||