Wednesday, January 6, 2016

Bluetooth (BLE) Robot Remote Control using an iPhone - Part 1

Overview


Any self respecting autonomous robot needs a remote control / telemetry mode. This is useful for testing and most importantly fun! There are lots of different ways that you could approach this (e.g. hard wired, WiFi, or RF) but we liked the idea of using our iPhone as the controller and this seemed like a good excuse to play around with Bluetooth.

Figure 1. The Bluno - Arduino Uno + BLE.

As this is a fairly meaty subject, we will break it up into three posts. Each post will cover the following:

  1. Bluno - An Arduino board combined with a Bluetooth 4 Low Energy module produced by DFRobot (see Figure 1). In our design this acts as the middle-ware, providing a bridge between our iPhone app and the Arduino Mega 2560 which acts as our main robot controller. You could control a simple robot directly from the Bluno. We also used the Bluno accessory shield, mostly to provide an indication of what is happening via its OLED display. However, this doesn't leave a lot of spare pins (3 digital and 2 analog to be precise).
  2. iOS App - I will provide the source code for this and make it available for download from iTunes once I have finished debugging. It should be flexible enough to use in your own robot design. I have included the ability to remap the keys should you wish to use different characters to the ones I selected.
  3. Mega 2560 Integration - This is the final step in allowing your robot to be controlled via an iPhone app. The Bluno communicates with the Mega 2560 using the serial 3 comms port. We could have used the I2C bus, but as this is used for logging it could be tied up when a critical stop command was trying to be sent from the remote. As a remote command is one of the highest priority behaviours, it made sense for it to have its own dedicated communication channel.

The Design


The wiring is simple. As shown in Figure 2, the Bluno connects to our Mega 2560 using 2 wires. Pins 4 and 5 of the Bluno connects to pins 14 and 15 on the Mega 2560 (the Serial 3 Tx and Rx pins). That's it, the magic happens in the software. We have described in an earlier post how the Mega 2560 controls our HB-25 Motor Controllers. Bluno uses a TI CC2540 BT 4.0 chip to provide BLE functionality. We will use this to communicate with the iPhone.

Figure 2. AVA Schematic.


The Hardware


We are using the SoftwareSerial library on the Bluno so you can use any 2 spare digital pins, but if you also use the accessory shield (Figure 3) then you wont have many other options. The accessory shield provides quite a bit of capability.


128x64 OLED Screen                                    Display messages from your phone interface.
Buzzer                                                            Enable Sound notifications or simple music.
DHT11 Temperature & Humidity Sensor     For environmental monitoring.
1.5A Relay                                                     Device switch or integrating with other electronics.
Helical Potentiometer                                    Transfer real time data to your phone
RGB LED                                                      Display full colour RGB
Mini Joystick                                                 Tells your phone which direction is pressed


The pins used by BLE module and the accessory shield are:

0    BLE Rx (also used for programming and for the terminal comms).
1    BLE Tx (also used for programming and for the terminal comms).
2    DHT11 Temp / Humidity sensor.
3    RGB LED (blue control).
4    Spare - used for serial Rx, connects to Mega 2560 Tx.
5    Spare - used for serial Tx, connects to Mega 2560 Rx.
6    OLED RESET
7    OLED DC
8    Buzzer
9    RGB LED (red control)
10  RGB LED (green control)
11  Relay
12  Spare
13  LED

A0    Joystick
A1    Knob (potentiometer)
A2    Spare
A3    Spare
A4    I2C - SDA
A5    I2C - SCL

Figure 3. The DFRobot Accessory Shield.

Looking at Figure 3 you will note our first design problem. None of the pins are accessible without breaking out the soldering iron. To allow us to connect our 2 serial wires we purchased a prototyping screw terminal shield from DFRobot (Figure 4).

Figure 4. Prototyping Screw Terminal Shield.

The proto shield is sandwiched between the Bluno and the accessory shield (Figure 5). Excellent we now have access to pins 4 and 5, BUT now the OLED display no longer works. Design problem number 2. For some unfathomable reason (particularly since all these products come from the same supplier) the proto shield is 2 pins short. The missing pins are the I2C SDA and SCL (used to control the OLED). There are a number of ways you can fix this, but the easiest is to get an Arduino Header Kit (like the one shown in Figure 5) and use the 6 pin header to bridge between the Bluno and the accessory shield. There are holes in the proto shield to allow this (albeit not exactly in the right spot). Cut off the 4 unused pins to prevent them shorting on anything. You can solder the header kit onto the proto board if you want but we didn't find this necessary.

Figure 5. Arduino Header Kit.

The images below (Figure 6) show the boards connected together and mounted on AVA. The yellow and brown wires are the serial comms to the Mega 2560 and the red and green are power and go to the distribution board on the bottom deck. The board adjacent to the Bluno is used for monitoring of the 2 x 12V SLA batteries. The panel voltmeter displays the current battery voltage (11.5 VDC).



Figure 6. Bluno, Proto and Accessory Shield.

The Software


You can download the Bluno software from the Reefwing Gist Repository. The code is pretty straight forward. The Bluno waits until it receives data on its serial port from the BLE module and passes it to the Mega via another serial port. The RGB LED flashes blue once a second while waiting for data. It will flash green once when data is received. The iOS app allows you to select a number of tasks for the robot to perform. In Figure 6, you can see that the current task is task 2: Patrol. When task 1, Remote Control is selected, the RGB LED goes a solid red.

The main code loop is shown below. As we will see in the next post, the iPhone app sends a character code to indicate the command required (e.g. 's' means stop).

if (Serial.available())  {
        char data = Serial.read();
        commsDetected = true;
        switch (data) {
            case 's':
                Serial.write("Ack - STOP");
                megaSerial.write(data);
                break;
            case 'f':
                Serial.write("Ack - Forward");
                megaSerial.write(data);
                break;
            case 'b':
                Serial.write("Ack - Back");
                megaSerial.write(data);
                break;
            case 'l':
                Serial.write("Ack - Left");
                megaSerial.write(data);
                break;
            case 'r':
                Serial.write("Ack - Right");
                megaSerial.write(data);
                break;
            case 'w':
                Serial.write("Ack - F1");
                megaSerial.write(data);
                break;
            case 'x':
                Serial.write("Ack - F2");
                megaSerial.write(data);
                break;
            case 'y':
                Serial.write("Ack - F3");
                megaSerial.write(data);
                break;
            case 'z':
                Serial.write("Ack - F4");
                megaSerial.write(data);
                break;
            case '0':
                task = statusReport;
                taskDescription = "T0: Status";
                Serial.print(taskDescription);
                megaSerial.write(data);
                remoteControlled = false;
                break;
            case '1':
                task = remoteControl;
                taskDescription = "T1: Remote";
                Serial.print(taskDescription);
                megaSerial.write(data);
                remoteControlled = true;
                break;
            case '2':
                task = patrol;
                taskDescription = "T2: Patrol";
                Serial.print(taskDescription);
                megaSerial.write(data);
                remoteControlled = false;
                break;
            case '3':
                task = followIR;
                taskDescription = "T3: Follow IR";
                Serial.print(taskDescription);
                megaSerial.write(data);
                remoteControlled = false;
                break;
            case '4':
                task = avoidIR;
                taskDescription = "T4: Avoid IR";
                Serial.print(taskDescription);
                megaSerial.write(data);
                remoteControlled = false;
                break;
            default:
                char errorMsg[32];
                String error = "Unknown Command - ";
                error += data;
                error.toCharArray(errorMsg, 32);
                Serial.write(errorMsg);
                break;
        }
        Serial.println();
    }

No comments:

Post a Comment