mambo-angular-service
Advanced tools
Comparing version 0.0.2 to 0.0.4
export declare class MamboUUIDs { | ||
/** | ||
* Contains Command Instructions and Flight Params Characteristics | ||
* 9a66fa00-0800-9191-11e4-012d1540cb8e | ||
*/ | ||
static serviceUUIDa: string; | ||
/** | ||
* Contains Flight Status Characteristic | ||
* 9a66fb00-0800-9191-11e4-012d1540cb8e | ||
*/ | ||
static serviceUUIDb: string; | ||
static services: string[]; | ||
/** 9a66fa0b-0800-9191-11e4-012d1540cb8e */ | ||
static characteristic_command_instructions: string; | ||
/** 9a66fa0a-0800-9191-11e4-012d1540cb8e */ | ||
static characteristic_flight_params: string; | ||
/** 9a66fb0e-0800-9191-11e4-012d1540cb8e */ | ||
static characteristic_flightStatus: string; | ||
} |
11
codes.js
@@ -5,9 +5,20 @@ "use strict"; | ||
} | ||
/** | ||
* Contains Command Instructions and Flight Params Characteristics | ||
* 9a66fa00-0800-9191-11e4-012d1540cb8e | ||
*/ | ||
MamboUUIDs.serviceUUIDa = '9a66fa00-0800-9191-11e4-012d1540cb8e'; | ||
/** | ||
* Contains Flight Status Characteristic | ||
* 9a66fb00-0800-9191-11e4-012d1540cb8e | ||
*/ | ||
MamboUUIDs.serviceUUIDb = '9a66fb00-0800-9191-11e4-012d1540cb8e'; | ||
MamboUUIDs.services = [MamboUUIDs.serviceUUIDa, MamboUUIDs.serviceUUIDb]; | ||
/** 9a66fa0b-0800-9191-11e4-012d1540cb8e */ | ||
MamboUUIDs.characteristic_command_instructions = '9a66fa0b-0800-9191-11e4-012d1540cb8e'; | ||
/** 9a66fa0a-0800-9191-11e4-012d1540cb8e */ | ||
MamboUUIDs.characteristic_flight_params = '9a66fa0a-0800-9191-11e4-012d1540cb8e'; | ||
/** 9a66fb0e-0800-9191-11e4-012d1540cb8e */ | ||
MamboUUIDs.characteristic_flightStatus = '9a66fb0e-0800-9191-11e4-012d1540cb8e'; | ||
exports.MamboUUIDs = MamboUUIDs; | ||
//# sourceMappingURL=codes.js.map |
@@ -1,2 +0,1 @@ | ||
/// <reference types="web-bluetooth" /> | ||
export declare class DroneCharacteristic { | ||
@@ -6,5 +5,5 @@ private characteristic; | ||
private characteristicUUID; | ||
private _steps; | ||
private readonly steps; | ||
constructor(characteristic: BluetoothRemoteGATTCharacteristic); | ||
private _step; | ||
private nextStep(); | ||
constructor(characteristic: any); | ||
private prepareBuffer(params); | ||
@@ -11,0 +10,0 @@ write(command: number[]): Promise<any>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class DroneCharacteristic { | ||
// constructor(private characteristic: BluetoothRemoteGATTCharacteristic) { | ||
constructor(characteristic) { | ||
this.characteristic = characteristic; | ||
this._steps = 0; | ||
this._step = 0; | ||
} | ||
get steps() { | ||
if (++this._steps > 255) { | ||
this._steps = 0; | ||
nextStep() { | ||
if (++this._step > 255) { | ||
this._step = 0; | ||
} | ||
return this._steps; | ||
return this._step; | ||
} | ||
prepareBuffer(params) { | ||
const buffer = [2, this.steps, 2].concat(params); | ||
const buffer = [2, this.nextStep(), 2, ...params]; | ||
return new Uint8Array(buffer); | ||
@@ -20,2 +21,3 @@ } | ||
const value = this.prepareBuffer(command); | ||
// [web-ble] Send command | ||
return this.characteristic.writeValue(value); | ||
@@ -25,2 +27,3 @@ } | ||
const value = this.prepareBuffer(command); | ||
// [web-ble] Send command | ||
this.characteristic.writeValue(value); | ||
@@ -27,0 +30,0 @@ return Promise.resolve(); |
/// <reference types="web-bluetooth" /> | ||
import { Observable } from 'rxjs'; | ||
export declare class Drone { | ||
private server; | ||
private device; | ||
private flightCommandInstructions; | ||
private flightParamsInstructions; | ||
private flightStatus; | ||
private batteryStatus; | ||
private roll; | ||
private pitch; | ||
private yaw; | ||
private altitude; | ||
roll: number; | ||
pitch: number; | ||
yaw: number; | ||
altitude: number; | ||
private flightLoopHandle; | ||
private loopHandle; | ||
private ready; | ||
constructor(server: BluetoothRemoteGATTServer); | ||
private connectionSubject; | ||
readonly connection$: Observable<boolean>; | ||
constructor(device: BluetoothDevice); | ||
connect(): Promise<any>; | ||
initialise(server: BluetoothRemoteGATTServer): Promise<void>; | ||
private prepareCharacteristics(server); | ||
private initialiseFlightDefaults(); | ||
onDisconnected(): void; | ||
private listenToOnDisconnected(); | ||
private onDisconnected(); | ||
/** | ||
@@ -41,5 +46,21 @@ * Convenience method for setting the drone's altitude limitation | ||
private stopFlightLoop(); | ||
/** | ||
* Instructs the drone to take off | ||
*/ | ||
takeOff(): void; | ||
/** | ||
* Instructs the drone to land | ||
*/ | ||
land(): void; | ||
/** | ||
* Instructs the drone to fire the cannon | ||
*/ | ||
fire(): void; | ||
/** | ||
* Sets the roll, pitch, yaw and altitude of drone's flight params in one call | ||
* @param roll turn speed, expected value from -1 (move left) to 1 (move right) | ||
* @param pitch turn speed, expected value from -1 (move back) to 1 (move forward) | ||
* @param yaw turn speed, expected value from -1 (turn counter-clocwise) to 1 (turn clocwise) | ||
* @param altitude turn speed, expected value from -1 (move down) to 1 (move up) | ||
*/ | ||
private sendFlightParams(); | ||
@@ -46,0 +67,0 @@ updateFlightParams(roll: number, pitch: number, yaw: number, altitude: number): void; |
101
drone.js
@@ -11,8 +11,7 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const rxjs_1 = require("rxjs"); | ||
const _1 = require("."); | ||
const FLIGHT_STATUSES = ['landed', 'taking off', 'hovering', 'flying', | ||
'landing', 'emergency', 'rolling', 'initializing']; | ||
class Drone { | ||
constructor(server) { | ||
this.server = server; | ||
constructor(device) { | ||
this.device = device; | ||
this.roll = 0; | ||
@@ -25,15 +24,39 @@ this.pitch = 0; | ||
} | ||
get connection$() { | ||
return this.connectionSubject.asObservable(); | ||
} | ||
connect() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const serviceA = yield this.server.getPrimaryService(_1.MamboUUIDs.serviceUUIDa); | ||
const serviceB = yield this.server.getPrimaryService(_1.MamboUUIDs.serviceUUIDb); | ||
this.flightCommandInstructions = new _1.DroneCharacteristic(yield serviceA.getCharacteristic(_1.MamboUUIDs.characteristic_command_instructions)); | ||
this.flightParamsInstructions = new _1.DroneCharacteristic(yield serviceA.getCharacteristic(_1.MamboUUIDs.characteristic_flight_params)); | ||
this.flightStatus = yield serviceB.getCharacteristic(_1.MamboUUIDs.characteristic_flightStatus); | ||
this.connectionSubject = new rxjs_1.Subject(); | ||
// [web-ble] Connect to the device | ||
const server = yield this.device.gatt.connect(); | ||
console.log('Drone connected'); | ||
yield this.initialise(server); | ||
}); | ||
} | ||
initialise(server) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield this.prepareCharacteristics(server); | ||
yield this.initialiseFlightDefaults(); | ||
this.startFlightLoop(); | ||
this.listenToOnDisconnected(); | ||
yield this.flightStatus.startNotifications(); | ||
this.ready = true; | ||
this.connectionSubject.next(true); | ||
console.log('Drone ready to fly'); | ||
}); | ||
} | ||
prepareCharacteristics(server) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// [web-ble] Get Services | ||
const instructionService = yield server.getPrimaryService(_1.MamboUUIDs.serviceUUIDa); | ||
const notificationService = yield server.getPrimaryService(_1.MamboUUIDs.serviceUUIDb); | ||
this.flightCommandInstructions = new _1.DroneCharacteristic( | ||
// [web-ble] Get Commands Characteristic | ||
yield instructionService.getCharacteristic(_1.MamboUUIDs.characteristic_command_instructions)); | ||
this.flightParamsInstructions = new _1.DroneCharacteristic( | ||
// [web-ble] Get Flight Params Characteristic | ||
yield instructionService.getCharacteristic(_1.MamboUUIDs.characteristic_flight_params)); | ||
this.flightStatus = yield notificationService.getCharacteristic(_1.MamboUUIDs.characteristic_flightStatus); | ||
}); | ||
} | ||
initialiseFlightDefaults() { | ||
@@ -51,5 +74,10 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
listenToOnDisconnected() { | ||
this.device.addEventListener('gattserverdisconnected', () => this.onDisconnected()); | ||
} | ||
onDisconnected() { | ||
console.log('Drone disconnected'); | ||
this.stopFlightLoop(); | ||
// this.flightStatus.stopNotifications(); | ||
this.connectionSubject.complete(); | ||
} | ||
@@ -92,40 +120,6 @@ /** | ||
} | ||
// listenToFlightStatus() { | ||
// const promise = this.flightStatus.startNotifying(); | ||
// this.flightStatus.getObservable().subscribe((notificationData: number[]) => { | ||
// this.updateFlightStatus(notificationData); | ||
// }); | ||
// return promise; | ||
// } | ||
// updateFlightStatus(notificationData: number[]) { | ||
// if (notificationData[2] !== 2) { | ||
// return; | ||
// } | ||
// const status = FLIGHT_STATUSES[notificationData[6]]; | ||
// this.flightStatusSubject.next(status); | ||
// console.log('updateFlightStatus::' + status); | ||
// } | ||
// stopListeningToFlightStatus() { | ||
// this.flightStatus.stopNotifying(); | ||
// } | ||
// listenToBatteryStatus() { | ||
// const promise = this.batteryStatus.startNotifying(); | ||
// this.batteryStatus.getObservable().subscribe((notificationData: number[]) => { | ||
// this.updateBatteryStatus(notificationData); | ||
// }); | ||
// return promise; | ||
// } | ||
// updateBatteryStatus(notificationData: number[]) { | ||
// const status = notificationData[notificationData.length-1]; | ||
// this.batteryStatusSubject.next(status); | ||
// console.log('updateBatteryStatus::' + status); | ||
// } | ||
// stopListeningToBatteryStatus() { | ||
// this.batteryStatus.stopNotifying(); | ||
// } | ||
startFlightLoop() { | ||
this.flightLoopHandle = setInterval(() => this.sendFlightParams(), 100); | ||
this.flightLoopHandle = window.setInterval(() => this.sendFlightParams(), 100); | ||
} | ||
stopFlightLoop() { | ||
debugger; | ||
if (this.flightLoopHandle > 0) { | ||
@@ -136,5 +130,11 @@ clearInterval(this.flightLoopHandle); | ||
} | ||
/** | ||
* Instructs the drone to take off | ||
*/ | ||
takeOff() { | ||
this.flightCommandInstructions.writeWithoutResponse([0, 1, 0]); | ||
} | ||
/** | ||
* Instructs the drone to land | ||
*/ | ||
land() { | ||
@@ -147,7 +147,16 @@ this.flightCommandInstructions.writeWithoutResponse([0, 3, 0]); | ||
} | ||
/** | ||
* Instructs the drone to fire the cannon | ||
*/ | ||
fire() { | ||
this.flightCommandInstructions.writeWithoutResponse([16, 2, 0, 0, 0, 0, 0, 0]); | ||
} | ||
/** | ||
* Sets the roll, pitch, yaw and altitude of drone's flight params in one call | ||
* @param roll turn speed, expected value from -1 (move left) to 1 (move right) | ||
* @param pitch turn speed, expected value from -1 (move back) to 1 (move forward) | ||
* @param yaw turn speed, expected value from -1 (turn counter-clocwise) to 1 (turn clocwise) | ||
* @param altitude turn speed, expected value from -1 (move down) to 1 (move up) | ||
*/ | ||
sendFlightParams() { | ||
console.log('sendFlightParams'); | ||
const command = [0, 2, 0, 1, this.roll, this.pitch, this.yaw, this.altitude, 0, 0, 0, 0, 0, 0, 0, 0]; | ||
@@ -154,0 +163,0 @@ this.flightParamsInstructions.writeWithoutResponse(command); |
@@ -0,6 +1,9 @@ | ||
/// <reference path="node_modules/@types/web-bluetooth/index.d.ts" /> | ||
import { Drone } from '.'; | ||
export declare class MamboService { | ||
constructor(); | ||
/** | ||
* Runs a bluetooth scan, this triggers a search pop up in the browser for the user to select a device. Once that is done, `search` returns a promise with the selected Drone object | ||
*/ | ||
search(): Promise<Drone>; | ||
onDisconnected(): void; | ||
} |
"use strict"; | ||
/// <reference path="./node_modules/@types/web-bluetooth/index.d.ts" /> | ||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
@@ -22,19 +23,18 @@ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
} | ||
/** | ||
* Runs a bluetooth scan, this triggers a search pop up in the browser for the user to select a device. Once that is done, `search` returns a promise with the selected Drone object | ||
*/ | ||
search() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const device = yield navigator.bluetooth.requestDevice({ | ||
// [web-ble] Search for Device | ||
const device = yield window.navigator.bluetooth.requestDevice({ | ||
filters: [{ namePrefix: 'Mambo' }], | ||
optionalServices: _1.MamboUUIDs.services | ||
}); | ||
const server = yield device.gatt.connect(); | ||
console.log('Drone ready to connect'); | ||
const drone = new _1.Drone(server); | ||
console.log('Connecting to drone...'); | ||
const drone = new _1.Drone(device); | ||
yield drone.connect(); | ||
console.log('Drone connected and ready to fly'); | ||
device.addEventListener('gattserverdisconnected', () => drone.onDisconnected()); | ||
return drone; | ||
}); | ||
} | ||
onDisconnected() { | ||
} | ||
}; | ||
@@ -45,2 +45,19 @@ MamboService = __decorate([ | ||
exports.MamboService = MamboService; | ||
// public search2() { | ||
// return new Observable(observer => { | ||
// let drone; | ||
// navigator.bluetooth.requestDevice( | ||
// { | ||
// filters: [{ namePrefix: 'Mambo' }], | ||
// optionalServices: MamboUUIDs.services | ||
// }).then(device => { | ||
// drone = new Drone(device); | ||
// drone.connect() | ||
// .then(() => { | ||
// observer.next(drone); | ||
// }); | ||
// }); | ||
// return () => drone && drone.disconnect(); | ||
// }) | ||
// } | ||
//# sourceMappingURL=mambo.service.js.map |
{ | ||
"name": "mambo-angular-service", | ||
"version": "0.0.2", | ||
"version": "0.0.4", | ||
"description": "Angular Service to control Parrot Mambo drone", | ||
@@ -40,2 +40,2 @@ "main": "index.js", | ||
} | ||
} | ||
} |
@@ -7,4 +7,51 @@ # mambo-angular-service | ||
First import `MamboService` in your `ngModule` then inject it in the component where you need to use it. | ||
You can `MamboService` to search for nearby drones. The search will pop up a search modal in the browser, allowing the user to select a device to connect to. | ||
When that happens the search returns the connected drone. | ||
``` | ||
this.mamboService.search().then(drone => this.drone = drone) | ||
``` | ||
Then use drone's `connect$` Observable to get notified when the connection has been fully established. Also the `connect$` completion indicates that the connection has been terminated. | ||
``` | ||
this.drone.connection$ | ||
.subscribe( | ||
() => this.ready, | ||
err => console.error('Something went wrong: ' + JSON.stringify(err)), | ||
() => { | ||
alert('Drone is no longer connected'); | ||
this.drone = null; | ||
this.ready = false; | ||
} | ||
); | ||
``` | ||
Once the drone is ready you can make the drone take off and land with the follownig calls: | ||
``` | ||
this.drone.takeOff(); | ||
this.drone.land(); | ||
``` | ||
By default every 100ms the `Drone object` sends flight parameters to the `Mambo drone`. You can provide the flight params by using the following functions: | ||
* setRoll | ||
* setPitch | ||
* setYaw | ||
* setAltitude | ||
* updateFlightParams | ||
Please note that the values that are expected should be in a range from -1 to 1. | ||
Just remember, if you set any of the flight params, the `Drone object` will send this value to the `Mambo drone` every 100ms, until you set it 0. | ||
If you intend for the drone to fly forward for some time you can call it like this: | ||
``` | ||
this.drone.setPitch(0.5); | ||
setInterval(() => this.drone.setPitch(0), 500 ); | ||
``` | ||
## API | ||
@@ -15,2 +62,3 @@ | ||
search(): Promise<Drone> | ||
* Runs a bluetooth scan, this triggers a search pop up in the browser for the user to select a device. Once that is done, `search` returns a promise with the selected Drone object. | ||
@@ -25,3 +73,3 @@ ### Drone | ||
#### `public updateFlightParams(roll: number, pitch: number, yaw: number, altitude: number)` | ||
#### `updateFlightParams(roll: number, pitch: number, yaw: number, altitude: number)` | ||
* Sets the roll, pitch, yaw and altitude of drone's flight params in one go | ||
@@ -33,15 +81,15 @@ * @param roll turn speed, expected value from -1 (move left) to 1 (move right) | ||
#### `public setRoll(roll)` | ||
#### `setRoll(roll)` | ||
* Sets the roll speed of drone's flight params | ||
* @param roll turn speed, expected value from -1 (move left) to 1 (move right) | ||
#### `public setPitch(pitch)` | ||
#### `setPitch(pitch)` | ||
* Sets the pitch of drone's flight params | ||
* @param pitch turn speed, expected value from -1 (move back) to 1 (move forward) | ||
#### `public setYaw(yaw: number)` | ||
#### `setYaw(yaw: number)` | ||
* Sets the turn speed of drone's flight params | ||
* @param yaw turn speed, expected value from -1 (turn counter-clocwise) to 1 (turn clocwise) | ||
#### `public setAltitude(altitude)` | ||
#### `setAltitude(altitude)` | ||
* Sets the altitude of drone's flight params | ||
@@ -66,3 +114,3 @@ * @param altitude turn speed, expected value from -1 (move down) to 1 (move up) | ||
#### `public fire()` | ||
#### `fire()` | ||
* Instructs the drone to fire the cannon |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
32291
490
112
18