Goal
In this tutorial, we will make Pepper lower his head as if looking at the ground just in front of him.
To do this, we will:
Prerequisites
Before stepping in this tutorial, you should be familiar with the action notion. For further details, see: Running Actions on Pepper.
Let’s start a new project
For further details, see: Creating a robot application.
We will create the target Frame, 1 meter in front of Pepper.
To retrieve this Frame, we will first need to get the robot frame.
The Robot Frame is provided by a service called Actuation.
We can retrieve it if we use the getActuation method on the
QiContext.
Put the following code in the onRobotFocusGained method:
// Get the Actuation service from the QiContext.
val actuation: Actuation = qiContext.actuation
// Get the Actuation service from the QiContext.
Actuation actuation = qiContext.getActuation();
Now we can get the robot frame:
// Get the robot frame.
val robotFrame: Frame = actuation.robotFrame()
// Get the robot frame.
Frame robotFrame = actuation.robotFrame();
Next, we create a 1 meter forward translation corresponding to the transform between the robot frame and the target frame:
// Create a transform corresponding to a 1 meter forward translation.
val transform: Transform = TransformBuilder.create().fromXTranslation(1.0)
// Create a transform corresponding to a 1 meter forward translation.
Transform transform = TransformBuilder.create().fromXTranslation(1);
We will now create the target frame.
The Mapping service provides a method to create a
FreeFrame:
 // Get the Mapping service from the QiContext.
val mapping: Mapping = qiContext.mapping
// Create a FreeFrame with the Mapping service.
val targetFrame: FreeFrame = mapping.makeFreeFrame()
// Get the Mapping service from the QiContext.
Mapping mapping = qiContext.getMapping();
// Create a FreeFrame with the Mapping service.
FreeFrame targetFrame = mapping.makeFreeFrame();
A FreeFrame represents a location free to be placed anywhere, that does not
move when other frames move.
The global position of a FreeFrame can be updated by applying a
Transform to a base Frame. The timestamp is left to 0, to update
targetFrame relatively to the last known location of robotFrame.
// Update the target location relatively to Pepper's current location.
targetFrame.update(robotFrame, transform, 0L)
// Update the target location relatively to Pepper's current location.
targetFrame.update(robotFrame, transform, 0L);
We now have the target frame. We will use it to build the lookat action.
You can make Pepper look at a Frame by using the LookAt interface.
Add a lookat field in your MainActivity:
// Store the LookAt action.
private var lookAt: LookAt? = null
// Store the LookAt action.
private LookAt lookAt;
We will create it with a LookAtBuilder in the onRobotFocusGained method:
// Create a LookAt action.
lookAt = LookAtBuilder.with(qiContext) // Create the builder with the context.
                             .withFrame(targetFrame.frame()) // Set the target frame.
                             .build() // Build the LookAt action.
// Create a LookAt action.
lookAt = LookAtBuilder.with(qiContext) // Create the builder with the context.
                             .withFrame(targetFrame.frame()) // Set the target frame.
                             .build(); // Build the LookAt action.
Next, we will set the LookAtMovementPolicy to use:
// Set the LookAt policy to look with the head only.
lookAt?.policy = LookAtMovementPolicy.HEAD_ONLY
// Set the LookAt policy to look with the head only.
lookAt.setPolicy(LookAtMovementPolicy.HEAD_ONLY);
The LookAtMovementPolicy parameter is set to HEAD_ONLY so that Pepper
only moves his head when looking at the specified Frame.
The LookAt interface has a addOnStartedListener method that allows you
to be notified when the LookAt action starts. We will use it to log to
the console:
// Add an on started listener on the LookAt action.
lookAt?.addOnStartedListener { Log.i(TAG, "LookAt action started.") }
// Add an on started listener on the LookAt action.
lookAt.addOnStartedListener(() -> Log.i(TAG, "LookAt action started."));
Do not forget to remove this listener on LookAt in the
onRobotFocusLost method:
// Remove on started listeners from the LookAt action.
lookAt?.removeAllOnStartedListeners()
// Remove on started listeners from the LookAt action.
if (lookAt != null) {
    lookAt.removeAllOnStartedListeners();
}
Store a Future<Void> in the MainActivity:
// Store the action execution future.
private var lookAtFuture: Future<Void>? = null
// Store the action execution future.
private Future<Void> lookAtFuture;
It will be used to keep a reference on the action execution.
We will now run the LookAt action asynchronously:
// Run the LookAt action asynchronously.
lookAtFuture = lookAt?.async()?.run()
// Run the LookAt action asynchronously.
lookAtFuture = lookAt.async().run();
We will finally chain the lookAtFuture with a lambda:
// Add a lambda to the action execution.
lookAtFuture?.thenConsume { future ->
    if (future.isSuccess) {
        Log.i(TAG, "LookAt action finished with success.")
    } else if (future.isCancelled) {
        Log.i(TAG, "LookAt action was cancelled.")
    } else {
        Log.e(TAG, "LookAt action finished with error.", future.error)
    }
}
// Add a lambda to the action execution.
lookAtFuture.thenConsume(future -> {
    if (future.isSuccess()) {
        Log.i(TAG, "LookAt action finished with success.");
    } else if (future.isCancelled()) {
        Log.i(TAG, "LookAt action was cancelled.");
    } else {
        Log.e(TAG, "LookAt action finished with error.", future.getError());
    }
});
The LookAt action needs to be cancelled to stop its execution.
The way to cancel this action is to call the requestCancellation method on
the Future representing the action execution:
lookAtFuture?.requestCancellation()
lookAtFuture.requestCancellation();
We will use a Button to cancel the action.
In the activity_main.xml layout file, add the following Button:
<Button
    android:id="@+id/cancel_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="Cancel action"/>
Set the button onClick listener in the onCreate method.
// Set the button onClick listener.
cancel_button.setOnClickListener {
    lookAtFuture?.requestCancellation()
}
// Find the button in the view in the onCreate method.
Button cancelButton = (Button) findViewById(R.id.cancel_button);
// Set the button onClick listener.
cancelButton.setOnClickListener(v -> {
    if (lookAtFuture != null) {
        lookAtFuture.requestCancellation();
    }
});
 The sources for this tutorial are available on GitHub.
 The sources for this tutorial are available on GitHub.
| Step | Action | 
|---|---|
| Install and run the application. For further details, see: Running an application. | |
| Choose “Stare somewhere”. 
 If you click on the cancel button: 
   | 
You are now able to make Pepper look at something!