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.
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!