Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorials:intermediate:pepper_shopping [2020/08/19 09:19] derricktutorials:intermediate:pepper_shopping [2022/02/08 14:11] (current) – [Creating an ASDF system for the cram_pepper_demo] sarthou
Line 1: Line 1:
-====== Pepper robot shopping assistant (tutorial in construction) ======+====== Pepper Robot Shopping Assistant ======
  
 ===== Setting Up The Workspace ===== ===== Setting Up The Workspace =====
  
 This process assumes you have already installed CRAM on your laptop. If not, please visit the installation section.  This process assumes you have already installed CRAM on your laptop. If not, please visit the installation section. 
-If you are using the image version of CRAM, please follow the next section.+If you are using the image version of CRAM, please follow the next section. Please note that Ubuntu 16.04 was used for this project.
  
 ==== VM Set Up ==== ==== VM Set Up ====
Line 11: Line 11:
  
 <code> <code>
-$ sudo apt update && sudo apt upgrade  +$ sudo apt-get update && sudo apt-get upgrade 
 </code> </code>
  
Line 17: Line 17:
  
 <code> <code>
-$ cd ~/workspace/ros/ +$ sudo apt-get install ros-kinetic-joint-state-publisher-gui
-$ sudo apt install ros-kinetic-joint-state-publisher-gui+
 $ sudo apt-get install ros-kinetic-pepper-meshes    $ sudo apt-get install ros-kinetic-pepper-meshes   
 </code> </code>
Line 28: Line 27:
 <code> <code>
 $ sudo apt-get install ros-kinetic-ros-control ros-kinetic-ros-controllers $ sudo apt-get install ros-kinetic-ros-control ros-kinetic-ros-controllers
-$ sudo apt install ros-melodic-roslisp-common  +$ sudo apt-get install ros-kinetic-roslisp-common  
 </code> </code>
  
-At this point, we need an older version of CRAM. We a specific branch of the CRAM architecture. Therefore, if you have some work done in the current version of CRAM, please make copy and place it in a different directory for safekeeping or commit your current branch.+At this point, we need an older version of CRAM. We need a specific branch of the CRAM architecture. Therefore, if you have some work done in the current version of CRAM, please create backup or commit your current branch before you proceed.
  
 Run the following in your terminal. Run the following in your terminal.
Line 37: Line 36:
 <code> <code>
 $ cd ~/workspace/ros/src/cram $ cd ~/workspace/ros/src/cram
 +$ git pull
 $ git checkout 3f5b268504cb5226709daa7a5d52364c2b05a93d $ git checkout 3f5b268504cb5226709daa7a5d52364c2b05a93d
 $ git branch  $ git branch 
Line 45: Line 45:
 ==== Native Set Up ==== ==== Native Set Up ====
  
-If you did a native installation of ROS and CRAM, you would most likely install all the necessary components. However, you have to go through the setup process for the VM to be sure everything is setup. Otherwise, skip to the part where you change the branch, then you are set to go.+If you did a native installation of ROS and CRAM, you would most likely install all the necessary components. However, you have to go through the setup process for the VM to be sure everything is setup. Otherwise, skip to the part where you update the repository and change the branch, then you are set to go.
  
 Now let's begin. Now let's begin.
Line 113: Line 113:
 Comment out the following code by putting semi-colon in front of them. It should be on line 40 - 43. Comment out the following code by putting semi-colon in front of them. It should be on line 40 - 43.
  
-<code>+<code lisp>
 ; (desig:register-location-generator ; (desig:register-location-generator
 ;  3 robot-current-pose-tf-generator ;  3 robot-current-pose-tf-generator
Line 127: Line 127:
 </code> </code>
  
-==== Uploading Models to the Parameter Server ====+===== Uploading Models to the Parameter Server =====
  
 After successfully building the package, we need to add the models we will be uploading to the ROS parameter server. Change directory to the pepper_description package, and let's create three folders, namely //launch//, //meshes//, and //urdf//. After successfully building the package, we need to add the models we will be uploading to the ROS parameter server. Change directory to the pepper_description package, and let's create three folders, namely //launch//, //meshes//, and //urdf//.
Line 220: Line 220:
 {{ :tutorials:intermediate:finalscene.png?nolink&800 |}} {{ :tutorials:intermediate:finalscene.png?nolink&800 |}}
  
-==== CRAM_Pepper Description ====+===== CRAM_Pepper Description =====
  
 We want to visualize our robot and shelves in the CRAM bullet world, but first, we need to map the various parts of the URDF to their functionality. CRAM needs to know which part of the robot is meant to do what. We want to visualize our robot and shelves in the CRAM bullet world, but first, we need to map the various parts of the URDF to their functionality. CRAM needs to know which part of the robot is meant to do what.
Line 252: Line 252:
 Since we have already done an example, let’s go ahead and replace everything in the package.xml with the following: Since we have already done an example, let’s go ahead and replace everything in the package.xml with the following:
  
-<code>+<code XML>
 <package format="2"> <package format="2">
   <name>cram_pepper_description</name>   <name>cram_pepper_description</name>
Line 275: Line 275:
 Next, let us replace everything in the //CmakeLists.txt// with the following: Next, let us replace everything in the //CmakeLists.txt// with the following:
  
-<code>+<code lisp>
 cmake_minimum_required(VERSION 2.8.3) cmake_minimum_required(VERSION 2.8.3)
 project(cram_pepper_description) project(cram_pepper_description)
Line 290: Line 290:
 By now, you should have done the beginner tutorial, which explains all about .asd files. Therefore let's create one for our cram_pepper_description. Create a file //cram-pepper-description.asd// and put the following code in it. By now, you should have done the beginner tutorial, which explains all about .asd files. Therefore let's create one for our cram_pepper_description. Create a file //cram-pepper-description.asd// and put the following code in it.
  
-<code>+<code lisp>
 (defsystem cram-pepper-description (defsystem cram-pepper-description
   :depends-on (cram-prolog   :depends-on (cram-prolog
Line 316: Line 316:
 Let’s define our package in the "//package.lisp//" file with the following code. Let’s define our package in the "//package.lisp//" file with the following code.
  
-<code>+<code lisp>
 (in-package :cl-user) (in-package :cl-user)
  
Line 331: Line 331:
 In the “//neck.lisp//” file, copy the following code, and paste it in there. In the “//neck.lisp//” file, copy the following code, and paste it in there.
  
-<code>+<code lisp>
 (in-package :pepper-descr) (in-package :pepper-descr)
  
Line 379: Line 379:
 Next, we need to do the same for the arms of the robot. Again, copy the following code and paste it in the "//arms.lisp//" file. Next, we need to do the same for the arms of the robot. Again, copy the following code and paste it in the "//arms.lisp//" file.
  
-<code>+<code lisp>
 (in-package :pepper-descr) (in-package :pepper-descr)
  
Line 494: Line 494:
 Finally, we need to provide a general knowledge of the robot. We do this in the "//general-knowledge.lisp//" file. Once again, copy the following code and paste it in the file. Finally, we need to provide a general knowledge of the robot. We do this in the "//general-knowledge.lisp//" file. Once again, copy the following code and paste it in the file.
  
-<code>+<code lisp>
 (in-package :pepper-descr) (in-package :pepper-descr)
  
Line 550: Line 550:
 Now let’s see if we can load our cram package in Emacs.  Now let’s see if we can load our cram package in Emacs. 
  
-First, run the following.+First, run the following in your terminal.
  
 <code> <code>
Line 581: Line 581:
 To be able to visualize our robot and shelves, let's set up our demo folder. To be able to visualize our robot and shelves, let's set up our demo folder.
  
-==== CRAM Pepper Demo ====+===== CRAM Pepper Demo =====
  
 Just like the //cram_pepper_description//, let’s create a new package in //cram_pepper// called //cram_pepper_demo// Just like the //cram_pepper_description//, let’s create a new package in //cram_pepper// called //cram_pepper_demo//
Line 607: Line 607:
 As explained before, open the //package.xml// file in any text editor and replace everything with the following code. As explained before, open the //package.xml// file in any text editor and replace everything with the following code.
  
-<code>+<code XML>
 <package format="2"> <package format="2">
   <name>cram_pepper_demo</name>   <name>cram_pepper_demo</name>
Line 668: Line 668:
 Next, replace open the //CmakeLists.txt// in any text editor and replace everything with the following code.  Next, replace open the //CmakeLists.txt// in any text editor and replace everything with the following code. 
  
-<code>+<code lisp>
 cmake_minimum_required(VERSION 2.8.3) cmake_minimum_required(VERSION 2.8.3)
 project(cram_pepper_demo) project(cram_pepper_demo)
Line 762: Line 762:
 </code> </code>
  
-Next, download the following resource folder from here (Github link) and put the entire folder in the cram_pepper_demo package folder. The folder contains our products for the shop.+Next, download the resource folder from [[https://github.com/danricky/cram-pepper/tree/master/cram_pepper_demo/resource|here]] and put the entire folder in the cram_pepper_demo package folder. The folder contains our products for the shop.
  
 Compile the project, make sure to have the "roslaunch" running at the background, and open Emacs. Compile the project, make sure to have the "roslaunch" running at the background, and open Emacs.
Line 907: Line 907:
  
   )   )
-<code>+</code>
  
 This function creates the bullet-world, extracts the necessary information about the robot and the shelves from the ros-parameter server, spawns a static floor (plane), generates the shelves, and spawns the robot. This function creates the bullet-world, extracts the necessary information about the robot and the shelves from the ros-parameter server, spawns a static floor (plane), generates the shelves, and spawns the robot.
Line 1071: Line 1071:
 So far, so good. So far, so good.
  
-==== Pack arms ====+===== Pack Arms =====
  
 At this point, we don’t want our robot arm looking a zombie. So let’s naturally park the arms. At this point, we don’t want our robot arm looking a zombie. So let’s naturally park the arms.
Line 1101: Line 1101:
 {{ :tutorials:intermediate:parkarm.png?nolink&600 |}} {{ :tutorials:intermediate:parkarm.png?nolink&600 |}}
  
-==== Import human ====+===== Import Human =====
  
 Now let’s bring in the human avatar. Let’s create a function for that as well. Append the following code to the “cram-plans.lisp” file. Now let’s bring in the human avatar. Let’s create a function for that as well. Append the following code to the “cram-plans.lisp” file.
Line 1131: Line 1131:
 Now that we have our human in the scene, we need to reposition the robot to face the human. It may be perceived as rude for the robot to turn the back to the human.  Now that we have our human in the scene, we need to reposition the robot to face the human. It may be perceived as rude for the robot to turn the back to the human. 
  
-==== Reposition Robot ====+===== Reposition Robot =====
  
 To reposition the robot, let's add the following function to the "cram-plans.lisp" file. To reposition the robot, let's add the following function to the "cram-plans.lisp" file.
Line 1610: Line 1610:
 Compile all your edited files and run the "interaction" function again. Select 1 in the first menu and 1 for the other menu. Your terminal should look like the image below. Compile all your edited files and run the "interaction" function again. Select 1 in the first menu and 1 for the other menu. Your terminal should look like the image below.
  
 +{{ :tutorials:intermediate:printonetest.png?nolink&600 |}}
 +
 +As we can see from the image above, the "cereal" can be located at three locations, which means that everything works up until this point. Let's parse the variables to the "demo-one" function.
 +Note: You can take out the print lines and replace those lines with the following code.
 +
 +<code lisp>
 +(demo-one ?productname ?productposelist)
 +</code>
 +
 +Update the "//demo-one//" function with the following code. Place it under the function details comment.
 +
 +<code lisp>
 +        (let*  ((shelf-pose-lists-copy ?shelf-pose-lists)
 + (product-name-copy ?product-name)
 + (product-pose nil)
 + (found nil))
 +
 +        ;;;expression
 + (dolist (?shelf-pose shelf-pose-lists-copy)
 +
 + (setf product-pose (generate-robot-pose ?shelf-pose))
 +
 + (cpl:with-retry-counters ((error-counter 2))
 + (cpl:with-failure-handling
 +
 + ((cram-common-failures:navigation-pose-unreachable (e)
 +
 +
 + (roslisp:ros-warn (navigation-failure) "~a~%
 + Could not move to location...retrying" e)
 +
 + (cpl:do-retry error-counter
 +
 + (setf product-pose (generate-robot-pose ?shelf-pose))
 +
 + (cpl:retry))
 + (return)))
 +
 +
 + (move-to-location product-pose)))
 +
 + )) ;;endof let* and dolist
 +</code>
 +
 +This code above creates four local variables. Using a loop, we go through the list of poses, and then we move the robot to a generated pose. Since CRAM allows us to handle failures, in some cases, the generated pose might be invalid or unachievable, so we try generating another pose for the robot to move to. We do this two times; however, you might want to do it more than once in reality. If we ran our "//demo-one//" function, we would see that the robot moves to all the locations. The image below shows the robot at the last location.
 +
 +{{ :tutorials:intermediate:robotmoveto.png?nolink&600 |}}
 +
 +Now we can proceed to find the product on the shelf.
 +
 +Let’s start by creating a function for that purpose. Copy the code below, and let's explain what is happening. 
 +
 +<code lisp>
 +;; This function finds a product based on the name
 +;; It tries to look for the product from a different direction on a shelf 
 +;; It also handles failures accordingly
 +(defun find-product (?product-name ?product-pose)
 +
 + (generate-look-directions ?product-pose)
 +
 + (let* ((?object-type (get-product-type ?product-name))
 + (possible-look-directions `(,*look-center*
 + ,*look-right*
 + ,*look-left*))
 + (?looking-direction (first possible-look-directions)))
 +
 + (setf possible-look-directions (cdr possible-look-directions))
 +
 + (move-to-location (calculate-robot-navigation-goal-towards-target ?looking-direction))
 +
 + (look-at-product ?looking-direction)
 +
 + (cpl:with-failure-handling
 + ((cram-common-failures:perception-object-not-found (e)
 +           ;; Try different look directions until there is none left.
 +           (when possible-look-directions
 +            (roslisp:ros-warn (perception-failure) "~a~%Turning head." e)
 +
 +            (format t "Changing viewing direction!")
 +            (setf ?looking-direction (first possible-look-directions))
 +
 +            (setf possible-look-directions (cdr possible-look-directions))
 +
 +            (move-to-location (calculate-robot-navigation-goal-towards-target ?looking-direction))
 +            (look-at-product ?looking-direction)
 +
 +
 +            (cpl:retry))
 +           (return)))
 +
 +
 + (cram-executive:perform
 + (desig:an action
 + (type detecting)
 + (object (desig:an object
 + (type ?object-type)))))
 + )))
 +</code>
 +
 +From the code above, we first generate three different looking directions based on the initial/given pose; center, left, and right with the following code.
 +
 +<code lisp>
 +(generate-look-directions ?product-pose)
 +</code>
 +
 +For every direction generated, we adjust the base of the robot to face that direction, and then we turn the robot's neck towards the position of the product. The reason behind this process depends on the pose of the robot at the initial state, turning only the neck towards the position of the product wouldn't be enough. Therefore, to compensate for the extra turn/distance, we adjust the robot base to make the turning neck, less strenuous.
 +
 +<code lisp>
 +(setf possible-look-directions (cdr possible-look-directions))
 +
 +(move-to-location (calculate-robot-navigation-goal-towards-target ?looking-direction))
 +
 +(look-at-product ?looking-direction)
 +</code>
 +
 +At this point, the robot should be in a position to detect the product. However, there is a probability that the detection could fail. That's the product that may not be available in a particular direction. This failure will cause our program to throw an error. Therefore, we can use the failure handling mechanism of CRAM to handle the error. In our program, we solve this problem by looking for the product in other directions (center, left, or right), and then we report back to the user.
 +
 +<code lisp>
 +(cpl:with-failure-handling
 + ((cram-common-failures:perception-object-not-found (e)
 +           ;; Try different look directions until there is none left.
 +           (when possible-look-directions
 +            (roslisp:ros-warn (perception-failure) "~a~%Turning head." e)
 +
 +            (format t "Changing viewing direction!")
 +            (setf ?looking-direction (first possible-look-directions))
 +
 +            (setf possible-look-directions (cdr possible-look-directions))
 +
 +            (move-to-location (calculate-robot-navigation-goal-towards-target ?looking-direction))
 +            (look-at-product ?looking-direction)
 +
 +
 +            (cpl:retry))
 +           (return)))
 +
 +
 + (cram-executive:perform
 + (desig:an action
 + (type detecting)
 + (object (desig:an object
 + (type ?object-type)))))
 + )
 +</code>
 +
 +From the code above, we can see that there some helper functions. These include "//generate-look-directions//", "//get-product-type//", "//calculate-robot-navigation-goal-towards-target//", and "//look-at-product//". We also introduced a few global variables. So let's add them to our "//cram-plans.lisp//" file.
 +
 +First, add the following global variables to the top of the page.
 +
 +<code lisp>
 +(defparameter *look-center* nil)
 +(defparameter *look-right* nil)
 +(defparameter *look-left* nil)
 +</code>
 +
 +Next, we add the following functions.
 +
 +<code lisp>
 +;; This function generates possible looking directions for the robot
 +(defun generate-look-directions (?product-pose)
 + (setf *look-center* (cl-transforms-stamped:pose->pose-stamped "map" 0  ?product-pose))
 + (setf *look-right* (get-right-pose ?product-pose))
 + (setf *look-left* (get-left-pose ?product-pose)))
 +</code>
 +
 +It contains some additional helper functions. Let’s add them.
 +
 +<code lisp>
 +;; This function generates the left possible looking direction
 +;; It takes the product name as an argument
 +(defun get-left-pose(?product-pose)
 + (let* ((mapTshelf-pose ?product-pose)
 + (mapTshelf-trans (cl-transforms:pose->transform mapTshelf-pose)))
 +
 + (cl-transforms-stamped:pose->pose-stamped "map"
 + (cl-transforms:transform->pose
 + (cl-transforms:transform* mapTshelf-trans *left-offset*)))))
 +
 +;; This function generates the right possible looking direction
 +;; It takes the product name as an argument
 +(defun get-right-pose(?product-pose)
 + (let* ((mapTshelf-pose ?product-pose)
 + (mapTshelf-trans (cl-transforms:pose->transform mapTshelf-pose)))
 + (cl-transforms-stamped:pose->pose-stamped "map"
 + (cl-transforms:transform->pose
 + (cl-transforms:transform* mapTshelf-trans *right-offset*)))))
 +</code>
 +
 +These helper functions contain some global variables, so let's place them at the top of the file.
 +
 +<code lisp>
 +(defparameter *right-offset* 
 + (cl-tf:make-transform (cl-tf:make-3d-vector 0.3 0.0 0.05) (cl-tf:make-quaternion 0 0 0 1)))
 +
 +(defparameter *left-offset* 
 + (cl-tf:make-transform (cl-tf:make-3d-vector -0.3 0.0 0.05) (cl-tf:make-quaternion 0 0 0 1)))
 +</code>
 +
 +Next,
 +
 +<code lisp>
 +;; This function queries our reasoning base and returns the type of 
 +;; product based on the name
 +(defun get-product-type(?product-name)
 + (cdaar (cut:force-ll (prolog `(and(is-of-type ,?product-name ?type))))))
 +
 +;; This function helps the robot to look at the given
 +;; location.
 +(defun look-at-product (?product-direction)
 + (cpl:with-retry-counters ((error-counter 2))
 + (cpl:with-failure-handling
 +
 + ((cram-common-failures:ptu-goal-not-reached (e)
 +
 +        (roslisp:ros-warn (perception-failure) "~a~%Looking at product went wrong...repositioning" e)
 +        (cpl:do-retry error-counter
 +
 +         (move-to-location (get-robot-new-pose))
 +
 +         (cpl:retry))
 +        (cpl:fail 'common-fail:looking-high-level-failure)))
 +
 +
 + (cram-executive:perform (desig:a action 
 + (type looking)
 + (target (desig:a location
 + (pose ?product-direction))))))))
 +</code>
 +
 +There is a helper function that repositions the robot in case the robot needs to increase its field of view. Let’s add that function.
 +
 +<code lisp>
 +;; This function generates and returns a new robot position based 
 +;; on its current position. It multiplies the current position of
 +;; the robot by an offset.
 +(defun get-robot-new-pose()
 + (let* ((robot-cur-pose (cram-tf:robot-current-pose))
 + (robot-cur-trans (cl-transforms:pose->transform robot-cur-pose)))
 +
 + (cl-transforms-stamped:pose->pose-stamped "map"
 + (cl-transforms:transform->pose
 + (cl-transforms:transform* robot-cur-trans  *robotPoseOffset*)))))
 +</code>
 +
 +This function contains a global variable to offset the position of the robot. Let's add that to a group of global variables.
 +
 +<code lisp>
 +(defparameter *robotPoseOffset* 
 + (cl-tf:make-transform (cl-tf:make-3d-vector -0.3 0.0 0.0) (cl-tf:make-quaternion 0 0 0 1)))
 +</code>
 +
 +Next,
 +
 +<code lisp>
 +;;;;
 +(defun calculate-robot-navigation-goal-towards-target (?location-pose)
 + (calculate-pose-towards-target
 + ?location-pose
 + (cram-tf:robot-current-pose)))
 +</code>
 +
 +This function also contains another helper function. Let’s add it.
 +
 +<code lisp>
 +;;"Given a `look-pose-stamped' and a `robot-pose-stamped' (both in fixed frame),
 +;; calculate the new robot-pose-stamped, which is rotated with an angle to point towards
 +;; the `look-pose-stamped'."
 +(defun calculate-pose-towards-target (look-pose-stamped robot-pose-stamped)
 +
 + (let* ((world->robot-transform
 + (cram-tf:pose-stamped->transform-stamped robot-pose-stamped "robot"))
 + (robot->world-transform
 + (cl-transforms:transform-inv world->robot-transform))
 + (world->look-pose-origin
 + (cl-transforms:origin look-pose-stamped))
 + (look-pose-in-robot-frame
 + (cl-transforms:transform-point
 + robot->world-transform
 + world->look-pose-origin))
 + (rotation-angle
 + (atan
 + (cl-transforms:y look-pose-in-robot-frame)
 + (cl-transforms:x look-pose-in-robot-frame))))
 + (cram-tf:rotate-pose robot-pose-stamped :z rotation-angle)))
 +</code>
 +
 +Now let’s call the find-product function after moving the robot to generated location. Append the following code to the “demo-one” function.
 +
 +<code lisp>
 +;; Finding product
 +(setf found (find-product product-name-copy ?shelf-pose))
 +</code>
 +
 +If we run "//demo-one//," we will notice that the robot will still go through all the possible product poses even if it finds it in the first position. Ideally, we want the robot to stop after seeing the product. Therefore, we need to check if the product has been found after every search. Let’s add the following code after trying to find the product.
 +
 +<code lisp>
 +(if (not (null found))
 + (return))
 +</code>
 +
 +This line of code will stop the search for the product after it has been found. If we try to run "demo-one," the robot should stop after the first try.
 +
 +
 +Suppose you have gotten to point without any issues kudos to you. We are almost done. Now, we need to point to the product on the shelf and move the human behind the robot. Let's add the necessary functions to perform these tasks. Update the "cram-plans.lisp" file with the following code.
 +
 +<code lisp>
 +(defun point-front-right() ; Point forward using the right arm
 + (cram-executive:perform
 + (desig:an action
 + (type positioning-arm)
 + (left-configuration park)
 + (right-configuration point-ahead))))
 +</code>
 +
 +Let's call this function when the product has been found. That's when "found" is not nil. We want to point to the product and then return. Therefore, we want to use the "progn" keyword. Update the demo-one function with the following code.
 +
 +<code lisp>
 +(if (not (null found))
 + (progn
 + (point-front-right)
 + (return)))
 +</code>
 +
 +Compile, and let's test the code to see if the robot will point to the product on the shelf. If everything is done correctly, you should have the robot point at the product, like the image below.
 +
 +{{ :tutorials:intermediate:pointing.png?nolink&600 |}}
 +
 +Now let’s bring the human closer to the robot. Let’s add the following functions.
 +
 +<code lisp>
 +;; This function moves the robot to a new position
 +(defun move-human-to-location()
 + (let* ((?new-human-location (get-human-new-pose)))
 + (setf (btr:pose (btr:object btr:*current-bullet-world* :my-human)) ?new-human-location)))
 +</code>
 +
 +This function has a helper function. Let’s add that as well.
 +
 +<code lisp>
 +;; This function generates and returns a new human position based 
 +;; on the robots position. It multiplies the current position of the robot
 +;; by an offset
 +(defun get-human-new-pose()
 + (let* ((robot-cur-pose (cram-tf:robot-current-pose))
 + (robot-cur-trans (cl-transforms:pose->transform robot-cur-pose)))
 + (cl-transforms-stamped:pose->pose-stamped "map"
 + (cl-transforms:transform->pose
 + (cl-transforms:transform* robot-cur-trans  *humanPoseOffset*)))))
 +</code>
 +We have a global variable in this function as well. Let’s add it at the top.
 +
 +<code lisp>
 +(defparameter *humanPoseOffset* 
 + (cl-tf:make-transform (cl-tf:make-3d-vector -0.8 0.0 1.0) (cl-tf:make-quaternion 0 0 1 1)))
 +</code>
 +
 +Now call it after the robot has pointed to the product. Like this;
 +
 +<code lisp>
 +(if (not (null found))
 + (progn
 + (point-front-right)
 + (move-human-to-location)
 + (return)))
 +</code>
 +
 +You should get the following results.
 +
 +{{ :tutorials:intermediate:movehuman.png?nolink&600 |}}
 +
 +Now let’s add some text to be printed to the terminal. Like the following:
 +
 +<code lisp>
 +(if (not (null found))
 + (progn
 + (point-front-right)
 + (move-human-to-location)
 + (format t "There is your product!")
 +(return)))
 +</code>
 +
 +Also, what happens when the product is not found? We need to add an else part to the if statement like the following.
 +
 +<code lisp>
 +(if (not (null found))
 + (progn
 + (point-front-right)
 + (move-human-to-location)
 + (format t "There is your product!")
 +(return))
 + (progn
 + (move-human-to-location)
 + (format t "Sorry I could not find your product! However, 
 + I believe it is supposed to be in this area of the shelf.")))
 +</code>
 +If we try running the "interaction" function after compiling, we will realize that the human avatar will not reset back to its original position. See the image below.
 +
 +{{ :tutorials:intermediate:stuckhuman.png?nolink&600 |}}
 +
 +So we need a function to reset the human back to its original position. Update the "cram-plans.lisp" file with the code below.
 +
 +<code lisp>
 +;;Repositions the human avatar 
 +(defun reposition-human()
 + (prolog:prolog '(and (btr:bullet-world ?world)
 +                              (assert (btr:object-pose ?world :my-human ((-1 0 1) (0 0 1 1)))))))
 +</code>
 +Let's call this function in the "interaction" function, like below.
 +
 +<code lisp>
 +;; Interaction execution
 +(defun interaction()
 + (cram-urdf-projection:with-simulated-robot (park-arms))
 + (reposition-human)
 + (reposition-robot)
 + (menu-one)
 +….
 +</code>
 +
 +Let's end the previous process using ctrl+c twice, compile the edited files, and run "interaction" again. You should see the human moving back to its original position.
 +
 +Congratulations!!! You just created a shopping assistant using the Pepper robot. 
 +
 +You can access the entire project from [[https://github.com/danricky/cram-pepper|here]]