Friday, January 16, 2015

Getting Started with Ollie and Android

Welcome internet denizens! I am an engineer on the Ollie project, and an avid supporter of the maker movement. I've decided to allocate some of my time to ensuring that you can all jump on the Bluetooth LE robot revolution! In particular, I plan on making a project entirely in our public SDK to work out any idiosyncrasies people on the outside might run into. In the process, I want to ensure that the public can follow in my footsteps.

Internally, we can only work on so much software. We don't even scratch the surface of what's possible with our robots! For that, I hope to see the creative juices of the internet kick into action. Do you make Ollie jump in excitement when you walk in your house? Maybe it's the handlebars of a motorcycle, or even the flight yolk of an airplane.

All great exploits have a humble beginning. To get started, I'd recommend acquiring the following packages:

For this tutorial, I will walk you through the basic steps necessary to connect to a robot. It does not handle any Android lifecycle events, reconnecting, or any other topics you may want before shipping your first Ollie project. If this post gets a good reception, I'll continue to update with my progress through a game.

To start out, lets create a project in Android Studio. I'll give mine a cool name like "GettingStarted"
Then I'll say I'm targeting Android 4.4. Talking to members of the SDK team, 4.3 should be supported and 4.2 may work. All the devices I own are on 4.4, and it's what I test on internally most often, so I'm choosing that to minimize any odd/esoteric issues with earlier BLE stacks.
For now I'm going to just use a "Blank Activity." Whatever you choose is up to your final app!
Lets choose a default name like "GettingStartedActivity."
The file we'll be most interested is our fancy new "GettingStartedActivity.java."

But before we write anything, we need to bring in "RobotLibrary.jar" to communicate with Ollie. To do this, right click on "app" and select "Open Module Settings."

Then click the "+" in the upper left and select "Import .JAR or .AAR Package."

Locate the "RobotLibrary.jar" that you downloaded before, and click "Finish."

Now you should have the "RobotLibrary" module in Android Studio. The last thing we want to do is make our project depend on it. For those of you just starting out, this means that our project needs RobotLibrary to work (which, if you plan on driving Ollie, it does). Select "app" under "Modules" on the left. Then select the "Dependencies" tab and click the "+" on the bottom to setup a "Module dependency."

Choose ":RobotLibrary" and you should be ready to get to the fun part!

Now I'll cover the basics on how to connect to an Ollie. I'd like to stress that I won't cover handling the application lifecycle. I'll include some notes at the end, and leave it as an exercise to the user until I'm bitten by the literary bug again.

To get started, lets put a "DiscoveryAgent" and "ConvenienceRobot" into our main activity. The former will find a robot for us, and the latter lets us send commands to it.



1
2
3
4
5
6
7
8
...
import com.orbotix.ConvenienceRobot;
import com.orbotix.common.DiscoveryAgent;

public class GettingStartedActivity extends ActionBarActivity {
private DiscoveryAgent _discoveryAgent;
private ConvenienceRobot _robot;
...

Now I'm going to create two helper classes. The first will just listen for discovery events, we'll just log that we're seeing robots. If we were connecting to Sphero, we'd use this to connect to the robot. Fortunately for us, Ollie will automatically connect when you get close enough!



1
2
3
4
5
6
7
 private DiscoveryAgentEventListener _discoveryAgentEventListener = new DiscoveryAgentEventListener() {
@Override
public void handleRobotsAvailable(List<Robot> robots) {
// for LE robots, we connect automagically
Log.i("Connecting", "Found " + robots);
}
};

This next class is pretty important, it will actually connect to Ollie and change his color to green. I'll cover "stopDiscovery()" in a second, so don't worry too much.


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
 private RobotChangedStateListener _robotStateListener = new RobotChangedStateListener() {
@Override
public void changedState(Robot robot, RobotChangedStateNotificationType robotChangedStateNotificationType) {
switch (robotChangedStateNotificationType) {
case Online:
Log.i("Connecting", robot + " Online!");
_robot = new Ollie(robot);
stopDiscovery();

_robot.setLed(0.f, 1.f, 0.f);
break;
}
}
};

Once we register this listener, it will return back to us with every state change. For now we just care about "Online." Here, you can listen for things like "Disconnected," "Offline," "Connecting," and "FailedConnect" to more robustly handle the various connection states. Once a robot comes online, we set its LED light to be green with the setLed call. The values are red, green, and blue and valid inputs range from 0 to 1. So setLed(0, 1, 0) will make ollie glow green. If we chose (1,1,1) it would be white and (0,0,0) would be off (not a very exciting test).

Now, lets actually connect to the robot. We'll add the following code to both start looking for a robot and to stop.


 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 private void startDiscovery() {
_discoveryAgent = DiscoveryAgentLE.getInstance();
_discoveryAgent.addDiscoveryListener(_discoveryAgentEventListener);
_discoveryAgent.addRobotStateListener(_robotStateListener);
try {
_discoveryAgent.startDiscovery(this);
} catch (DiscoveryException e) {
Log.e("Connecting", "Failed to start discovery because " + e);
e.printStackTrace();
}
}

private void stopDiscovery() {
_discoveryAgent.stopDiscovery();
_discoveryAgent.removeDiscoveryListener(_discoveryAgentEventListener);
_discoveryAgent.removeRobotStateListener(_robotStateListener);
_discoveryAgent = null;
}

Some importing lines to note. We call DiscoveryAgentLE.getInstance() to look for Ollie, we can change this to "DiscoveryAgentClassic" to look for Sphero. Additionally, we're registering those helper classes we made earlier in addDiscoveryListener and addRobotStateListener. Without these calls, we wouldn't get any notification.

Once we have everything setup, we call startDiscovery. One last note, it is ideal to remove all the listeners you registered before you shut down the app, but you won't get the disconnect callback if you unregister the _discoveryAgentEentListener. In your final code, you'd just want to call _discoveryAgent.stopDiscovery(); when a robot connects and call the .remove functions when your app is done with Ollie.

So we have all the code to connect to a robot, lets connect! Add "startDiscovery()" to onCreate like so:


1
2
3
4
5
6
7
 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_getting_started);

startDiscovery();
}

You're almost ready to hit run! We just need to do one more thing. In your "AndroidManifest.xml," you need to tell Android that we want to use BluetoothLE.


1
2
3
 <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

Of course, your users may start demanding why you need all these permissions. So lets break this down real fast:
"android.hardware.bluetooth_le" simply lets us use BLE rather than Bluetooth Classic. This is how Ollie communicates with your device.
"android.permission.BLUETOOTH" is pretty self-explanatory. This lets use use Bluetooth.
"android.permission.BLUETOOTH_ADMIN" sometimes scares people. This simply says that we'll discover and pair with devices. Many bluetooth devices like keyboards and speakers are paired with by the OS outside of our app. This is not the case with Ollie! He'll sit quietly for months looking for a friend to play with before your app comes by and wakes him up.

Now you should be up and running with an Ollie. Some things to try on your own:
  • Disconnect from Ollie when you enter the background
  • Support reconnecting to Ollie when he becomes disconnected (you can force a disconnect from the robot by plugging him in)
  • Try changing the colors a bit
  • Get him driving
If you have the entire Git repo pulled down, I recommend checking out the DriveSample for examples on how to use the SDK.

Happy Hacking!

Edit:
One more permission is required, it will crash sometimes if you forget to add it.


<uses-permission android:name="android.permission.INTERNET"/>

This is for collecting stats, which can be used to improve the SDK as well as the general Ollie experience.

3 comments:

Kotlin Game Programming