As the last step, I made an Android application to control the ESkateboard via bluetooth. It automatically scans my skateboard and tries to establish connection and it allows speed control from volume up/down button or touch screen(currently disabled as I found that using volume button was good enough for me). The full code can be accessed from my Github.
The UI of my application looks like this:
The application was modified from Android Bluetooth Low Energy example project from here. The structure of the application consists mainly two parts: the main activity and a service that bound to it. The activity takes care of all the input handling and UI display while the service takes care of Bluetooth communication.
Section 1: Bluetooth Communication
Upon clicking the connect button on the top right corner, the application scans for the BLE device of the skateboard and automatically tries to connect to it by comparing the MAC address of the found BLE device to the MAC address of the Arduino 101 used in my skateboard which is hard-coded as a constant string in my application.
The whole procedure could be summarized as follows:
1. If MAC address matches the constant string stored in application, store the found BluetoothDevice and then bind service (instantiate a service class object and bind it to MainActivity)
2. In OnServiceConnected callback, if service is bound, use a local binder to get the BLEService object.
3. Call the BLEService's public method to pass BluetoothDevice object stored to service.
4. Call the BLEService's public method to connect to BluetoothDevice
5. BLEService's will try to connect BluetoothDevice using BluetoothDevice.connectGatt() API.
6. If connection is successful, BLEService will use LocalBroadcastManager to broadcast an intent to MainActivity
7. MainActivity had a broadcast receiver registered in OnCreate(). Upon receiving any intent from BLEService, proper responses are executed.
After Bluetooth connection is properly established, speed command could be sent to Arduino 101 using BLEService.writeCharacteristics() API.
Section 2: Using Volume Button to Control Speed
If you use conventional radio controller or even the progress bar on the application screen, you have access to the full range of throttle and you can change speed or brake instantly. But as mentioned before, I wanted to use volume button to control speed as it would be more convenient and does not have the risk of misclick. In order to achieve this, I had to make some adjustments and compromises.
The speed command range was programmed to be from -10-90 (corresponding to progress bar progress 0-100). A value from -10 - 0 sets the brake strength and a value 0-90 sets the forward speed.
Naturally, I programmed volume up button to increase speed and volume down button to decrease speed. Furthermore, I programmed the amount of increase and decrease to 5 for forward speed as too small a number means it would take too long to adjust speed while too large a number would accelerate or decelerate skateboard too fast and cause potential danger. For brake strength, I programmed the amount to be 2 so there were in total 5 different brake strengths to choose from (-2,-4,-6,-8,-10). Although this method sacrificed a little resolution of speed control (now you can't set the speed to an arbitrary number such as 24), it did not cause too much a problem for me on road.
But how to brake instantly in face of danger? I programmed it so that long pressing volume down button would brake the skateboard with full strength. The long press triggers in about 1s so it is still risky if you are running at a relatively high speed. Therefore, I programmed such that the stop button on screen could also be pressed to brake the skateboard.
After some time riding the skateboard, I found out I was in need of a button to put skateboard instantly to neutral speed in order to pass some small obstacles or slide down a small slope. It took too long to set skateboard speed to neutral by pressing the volume down button multiple times.
Right now I am testing two methods, the first is long pressing volume up button and the second is press the progress bar (as control from the progress bar is disabled). Either way has the same effect. Take long pressing volume up button for example, doing that would put the skateboard to neutral speed. After the skateboard is set to neutral speed, you could either long press the volume up button again to restore the skateboard to its previous speed or you could adjust the speed or brake the skateboard using volume up or volume down button. If you go for the latter, the next long press on volume up button would not put the skateboard to neutral again.
This way of control is mainly from my experience of riding skateboard. Imagine if you are going to run over some small obstacles such as a road bump, you could long press volume up button to set the skateboard to neutral speed. After you pass the the road bump, you could long press volume up button again to instantly restore to your original speed. Or if you are going to ride down a slope, you could long press the volume up button to set the skateboard to neutral speed, and then use volume buttons to adjust brake strengths.
Volume button control is implemented by overriding onKeyUp(), onKeyDown(), onKeyLongPress() APIs. One can refer to the full code for details
Section 3: Extra Functions or Notes
What if someone calls while you are on skateboard? I programmed that if the application's onPause() method is called, the application will first send command to brake skateboard first. This is applicable if user accidentally presses the power button as well.
What if Bluetooth connection is lost? The Arduino 101 is programmed that if Bluetooth is not connected, it will always send zero speed command to ESC.
It turned out that if Android rotates the application for example from horizontal to vertical, it would first destroy the application and create it again which will cause the Bluetooth connection to drop. Furthermore, the same issue also happens if Android turns off screen due to power saving. So I disabled rotating of the application and turning off screen in code.
Another thing to notice is that since Android 6.0(API level 23), To use Bluetooth scans, the app must have the ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions for some reason. And if Android system does not grant this permission automatically, you need to ask for it at runtime.
No comments:
Post a Comment