Over a million developers have joined DZone.

Controlling Robots With NativeScript Bluetooth

DZone's Guide to

Controlling Robots With NativeScript Bluetooth

If you've ever wanted your own robot army, now is the time, and NativeScript Bluetooth is the medium. Learn how to create the app that will control your minions.

· Mobile Zone ·
Free Resource

Building an army of robots has never been easier than now. All you need is a team of obedient robots like Wowwee Mip and an app to control them. The Mip uses BLE (Bluetooth Low Energy) as the protocol for communication.

In this article, we will look into the core concepts of Bluetooth, how to use  nativescript-bluetooth  and how to build an app for the robot. We will also try to spice up the app with a bit of rxjs where applicable.

This article will focus solely on the mechanics of using Bluetooth, however, it won't provide any UI code. To see a fully working example, see nativescript-mip-simple-ng.

Bluetooth Core Concepts

Services, Characteristics, Instructions

Bluetooth commands are divided into a group of Services, like Dashboard service, Weapons service, and Drive Control service. Then each service contains a group of characteristics, for example, the Dashboard service contains Speed Indicator characteristic and Fuel Indicator characteristic.

Each service is designated to either receive read instructions to provide feedback (Dashboard service and its characteristics) or to receive write instructions to perform operations (Weapons and Drive Control services).

Note that each service and characteristic can be identified with the help of its UUID. The default services tend to be 4 characters long (i.e.  fa00 ) while other services are a bit longer and look like this:  9a66fb00-0800-9191-11e4-012d1540cb8e .

Image title

Steps to Communicate With BLE Devices

Regardless of what technology you use to communicate with a BLE device you always have to follow a similar set of steps:

  • Make sure Bluetooth is enabled and available.
  • Scan for BLE devices in the area.
  • Allow the user to select a device and connect.
  • Use Service + Characteristic to send Read/Write commands.

Working With a Wowee MiP Robot

For the purposes of this article we will be using Wowwee Mip.

Wowwee MiP robotIn order to send instructions to a MiP robot we need to use  serviceUUID = 'fe05'  and  characteristicUUID = 'ffe9' . Wowee has also prepared a MiP Protocol documentation that lists all available commands.

For example, the protocol provides us with the description of how to change the color of the chest LED. It contains the code for this instruction 0x84  and then the required parameters 3 byte values for Red, Green, and Blue.

So if we want to call it with an RGB value of FFAA88 , the command should be something like:  '0x84,0xFF,0xAA,0x88' 

NativeScript Bluetooth Plugin API

In NativeScript, the best plugin for Bluetooth communications is nativescript-bluetooth. It allows you to do everything you need to command an army of robots.


First, we need to add the plugin to your NativeScript project:

tns plugin add nativescript-bluetooth


Then we need to require the module.

For Vanilla JS use:

var bluetooth = require( "nativescript-bluetooth" );

For TypeScript (strongly recommended) use:

import bluetooth = require( 'nativescript-bluetooth' );

Check if Bluetooth is Available

Before we start communicating with the devices, we need to first check whether Bluetooth is enabled.

To do this, just call isBluetoothEnabled , which will return a promise with a boolean flag.

  enabled => console.log("Enabled? " + enabled)

We could spice this up a little with rxjs and create an Observable that will emit an event every time Bluetooth is enabled or disabled.

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/distinctUntilChanged';

listenToBluetoothEnabled(): Observable<boolean> {
  return new Observable(observer => {
      .then(enabled => observer.next(enabled))

    let intervalHandle = setInterval(
      () => {
          .then(enabled => observer.next(enabled))
      , 1000);

    // stop checking every second on unsubscribe
    return () => clearInterval(intervalHandle);

Then subscribe to it, so that we get notified about changes:

.subscribe(enabled => this.isBluetoothEnabled = enabled);

This gives as an elegant mechanism to handle this scenario and ask the user to enable Bluetooth if it is disabled.

Second, check/request app permissions to use Bluetooth. This step is only required for Android, as iOS handles this automatically.

To check the permissions, call:  bluetooth.hasCoarseLocationPermission() , which will return a promise with the result.

.then(granted =>
  console.log("Has Location Permission? " + granted);

If false, then you should request the permissions by calling:  bluetooth.requestCoarseLocationPermission() .

Hint: I tend to skip the permission check and always call the request function when I am loading the first page of my app. The plugin is smart enough to ignore my request if the permission has already been granted. For example, in an Angular project, I do it from ng0nInit like this:

ngOnInit() {    bluetooth.requestCoarseLocationPermission(); }


Once Bluetooth is ready to go, it is time for us to search for devices.

To do that we need to use the startScanning  function and provide how long you want to scan for as seconds  and a callback for each discovered device, as `onDiscovered`.

The two most important pieces of information we get from onDiscovered  are:

  • peripheral.name - which you can use to display to the user for selection.
  • peripheral.UUID - the UUID for this device, which you need to connect to the device.

We will use the results of onDiscovered  to populate  devices the array, which you can use to display the data in a listview.

private devices: any[] = [];

scan() {
  this.devices = [];

    seconds: 3,
    onDiscovered: (peripheral: Peripheral) => {
      if(peripheral.name) {
        console.log(`UUID: ${peripheral.UUID} name: ${peripheral.name}`)


If everything goes well you should see a list of devices including our MiP robot.

To connect to it we need to call the connect  function and provide:

  • UUID - the UUID of your device.
  • onConnected function - a callback function, which is called when the connection is fully established. Use this function to navigate to a view with device controls (like a view with goForward, goBack buttons).
  • onDisconnected function - a callback function, which is called when the device gets disconnected. Use this function to move back to the scanner view.
connect(UUID: string) {
    onConnected: (peripheral: Peripheral) => {
      //here you can navigate to the controller view
    onDisconnected: (peripheral: Peripheral) => {
      alert('Device Disconnected');
      //here you can navigate to the scan view

Scan Page Full Example

For a full example on how to check permissions, search and connect, see mip-scan.component.

Sending Commands

Once we are connected to our robot we can start sending some instructions.

According to the protocol, we can tell the robot to move forward and back using the below parameters. Move Forward and Back

To move forward at speed 20 for 500ms and we need provide the following values:

Image title

We can provide the value in two different ways:

  • as a String of comma separated hex values, i.e. value: '0x71,0x14,0x47'
  • as a Uint8Array with numeric values, i.e. value: new Uint8Array([0x71,0x14,0x47]) or value: new Uint8Array([0x71,20,71])

Hint: String seems to be a. good solution for hardcoded values, however, Uint8Array is much better when we need to deal with a constant stream of values coming from the UI.

To issue a command, we need to call the write  or the writeWithoutResponse  functions which take:

  • serviceUUID - in our case this is ffe5.
  • characteristicUUID - in our case this is ffe9.
  • peripheralUUID - in our case this is the UUID of the robot we connected to.
moveForward() {
    serviceUUID: 'ffe5',
    characteristicUUID: 'ffe9',
    peripheralUUID: this.deviceUUID,
    value: '0x71,0x14,0x47'

moveBack() {
    serviceUUID: 'ffe5',
    characteristicUUID: 'ffe9',
    peripheralUUID: this.deviceUUID,
    value: new Uint8Array([0x72,0x20,0x40])

Hint: writeWithoutResponse  is much faster than write , as it doesn't wait for the response from the device. Most of the time, you should use writeWithoutResponse  . You should use  write  only when you want to wait until the command has been received and processed by the connected device In the case of the MiP robot there is no need for that.

When I was working with a Parrot Mambo drone before I could send any flight instructions, I had to initialize it first by sending 4 config commands. Each command had to be sent after the previous one had been completed, which meant that I needed to use write  and wait for a promise until I could call the next one

Continuous Drive

I am sure that from this point you can figure out how to make the robot turn left and right. The four drive with time commands are easy to implement, however they don't give you the best possible driving experience. Luckily the robot has another function called Continuous Drive, which allows you to send driving instructions every 50ms for a smooth driving experience.

Image title

Since we are going to call Continuous Drive several times it is best to wrap it in an elegant function. Which will take speed and turn attributes (in the range from -1 to 1), convert them into hex and then call the writeWithoutResponse  function.

Note that to move forward we need to send values between 0 and 0x20, to go back we need to send values between 0x21 and 0x40. To turn left, we need to send values between 0x61 and 0x80 and to turn right we need to send values between 0x41 and 0x60.

* Converts speed and turn values into hex values exected by MiP
* and issues the Continuous Drive command
* @param speed Move Forward[0 to 1], Move Back[-1 to 0]
* @param turn Turn Left[-1 to 0], Turn Right[0 to 1]
continuousDrive(speed: number, turn: number) {
  const mipSpeed = (speed > 0) ? this.convertTo0x20(speed, 0) : this.convertTo0x20(speed, 0x20);
  const mipTurn = (turn > 0) ? this.convertTo0x20(turn, 0x40) : this.convertTo0x20(turn, 0x60);

    serviceUUID: this.serviceUUID,
    characteristicUUID: this.characteristicUUID,
    peripheralUUID: this.deviceUUID,
    value: new Uint8Array([0x78, mipSpeed, mipTurn])

convertTo0x20(val: number, offset: number) {
  if(val < 0) {
    val = -val;

  return Math.floor(val * 0x20) + offset;

Now we can call this in a loop to make the robot drive forward left in a circle.

  () => this.continuousDrive(0.5, -0.7)

Or if you have a speed and a turn parameters, which you can update from the UI, you could call it like:

  () => this.continuousDrive(this.speed, this.turn)


But really to get the most out of the Continuous Drive we need something that will give the user a way to continuously provide feedback to the robot.

This is where nativescript-accelerometer plugin comes in, as it will allow us to control the robot by tilting the phone.

First let's add the plugin to our project.

tns plugin add nativescript-accelerometer

Using the accelerometer is rather simple. The plugin provides two functions:

  • startAccelerometerUpdates - it takes a callback to return the phone position with x, y and z coordinates
  • stopAccelerometerUpdates - it stops accelerometer updates

However the accelerometer provides updates at a different frequency than every 50ms that we require for the Continuous Drive. To work around that we will use accelerometer updates to update turn (with data.x) and speed (with data.y`) attributes and separately start a time loop with `setInterval`, which will call Continuous Drive every 50ms.

Then we will need a separate function that will allow us to stop the accelerometer updates and the time loop:

private loopHandle: number = null;

startAccelerometerInterval() {
  // Ignore if accelerometer is already active
  if (this.loopHandle) {

  let turn: number = 0;
  let speed: number = 0;

  // Start accelerometer updates
    (data: AccelerometerData) => {
      turn = data.x;  //Tilt left [-1 to 0] Tilt right [0 to 1]
      speed = data.y; //Tilt back [-1 to 0] Tilt forward [0 to 1]

  //start the time loop
  this.loopHandle = setInterval(() => {
    this.continuousDrive(speed, turn);
  }, 50);

stopAccelerometerInterval() {
  if(this.loopHandle) {


    this.loopHandle = null;

Now if you call the startAccelerometerInterval function, you should be able make the robot drive forward or back by leaning it forward or back. And to make it turn just tilt it left or right. How cool is that?

Accelerometer With rxjs Observable

To spicy it up a little let's wrap the accelerometer functionality in an rxjs Observable. We need our observable to start accelerometer updates and emit all values, and in when unsubscribed it should stop the updates.

Before we subscribe to it we need to use sampleTime(50), which will only take the current value every 50ms and ignore all other value emitted in between. Then we can subscribe and on every update call continuousDrive. Just remember to capture the subscription object returned from the subscribe call.

Stopping the updates is as simple as calling unsubscribe on the subscription object, as the unsubscribe will take of stopping the accelerometer updates.

startAccelerometerRxjs() {
  // Create an Observable that emits accelerometer data
  const accelerometer$ = new Observable<AccelerometerData>(observer => {
      (data: AccelerometerData) => {
        // Emit the value for each update

    //Stop accelerometer on unsubscribe
    return () => stopAccelerometerUpdates();

  this.accelerometerSubscription = accelerometer$
  // receive current value every 50ms
  // Subscribe to the updates
  .subscribe(data => {
    this.continuousDrive(data.y, data.x)

stopAccelerometerRxjs() {

Controller Page Full Example

For a full example on how to make the robot drive around using drive with time functions and both accelerometer approaches, see mip-controller.component.

It is really easy to use NativeScript to talk to robots. The only things that limit you are the robot's API and your imagination. If you found this article interesting and you would like to impress your friends, you should get yourself a robot that supports BLE communication (in my case this was Wowwee MiP) and get your hands dirty.

For other examples, you could check out my plugin which wraps most of MiP's functionality. See nativescript-mip-ble.

Just remember the formula: Scan -> Connect -> Command.

mobile ,robots ,mobile apps ,mobile app development ,nativescript ,bluetooth

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}