Skip to content

crane-hiromu/DroidKit

Repository files navigation

DroidKit

Description

- Do you know 'Droid Inventor Kit' ?

littlebits-box-1-1024x686

(Quote: ‘TURN EVERYONE INTO AN INVENTOR’: THE STORY OF THE LITTLEBITS DROID INVENTOR KIT)


'Droid Inventor Kit' is a kit to create a droid. In addition, the droid can be operated with simple programming from a smartphone. However, there is a problem. Currently, the app has been removed from the store and cannot be installed. So I decided to provide code that can operate the droid from Swift. In short, you can create your own application with this Swift package.


- Sample Screen

App Color Picker Sound Menu Joystick

You can check the operation on DroidKitDebugView.

import SwiftUI
import DroidKit

struct ContentView: View {
    
    var body: some View {
        DroidKitDebugView()
    }
}

Don't forget to add bluetooth capability permission (NSBluetoothAlwaysUsageDescription) on your project.


Code

There are 2 core code in this package.

Inspired by tinkertanker/DroidKit and are also built on a 'Concurrency' basis with AsyncBluetooth.

- DroidConnector.swift

public protocol DroidConnectorProtocol: AnyObject {
    var eventPublisher: AnyPublisher<CentralManagerEvent, Never> { get }
    
    /// CentralManager Method
    func scan() async throws
    func connect() async throws
    func disconnect() async throws
    
    /// Peripheral Method
    func discoverServices() async throws
    func discoverCharacteristics() async throws
    func setNotifyValue(with characteristic: Characteristic) async throws
    func setNotifyValues() async throws
    func writeValue(command: UInt8, payload: [UInt8]) async throws
}

This code contains the implementation around Bluetooth. You can access it, but basically you don't have to do it.

- DroidOperator.swift

public protocol DroidOperatorProtocol: AnyObject {
    var eventPublisher: AnyPublisher<CentralManagerEvent, Never> { get }
    
    /// Connection Method
    func connect() async throws
    func disconnect() async throws
    
    /// Action Method
    func action(command: DroidCommand, payload: [UInt8]) async throws
    func go(at speed: Double) async throws
    func back(at speed: Double) async throws
    func turn(by degree: Double) async throws
    func stop() async throws
    func endTurn() async throws
    func changeLEDColor(to color: UIColor) async throws
    func playSound(_ type: DroidSound) async throws
    func wait(for seconds: Double) async throws
}

This code contains the implementation around droid operation. You can operate droid.


Document

The following actions can be used.

- connect

Turn on the connection.

Task {
    do {
        try await DroidOperator.default.connect()
    } catch {
        // catch error
    }
}

- disconnect

Turn off the connection.

Task {
    do {
        try await DroidOperator.default.disconnect()
    } catch {
        // catch error
    }
}

- go

Move forward.

Task {
    do {
        try await DroidOperator.default.go(at: 0.7)
    } catch {
        // catch error
    }
}

- back

Move back.

Task {
    do {
        try await DroidOperator.default.back(at: 0.3)
    } catch {
        // catch error
    }
}

- turn

Turn towards.

Task {
    do {
        try await DroidOperator.default.turn(by: 30)
    } catch {
        // catch error
    }
}

- stop

Stop moving.

Task {
    do {
        try await DroidOperator.default.stop()
    } catch {
        // catch error
    }
}

- endTurn

Reset wheel degree.

Task {
    do {
        try await DroidOperator.default.endTurn()
    } catch {
        // catch error
    }
}

- changeLEDColor

Change body's LED ramp color.

Task {
    do {
        try await DroidOperator.default.changeLEDColor(to: .blue)
    } catch {
        // catch error
    }
}

- playSound

Play sound from droid.

Task {
    do {
        try await DroidOperator.default.playSound(.s10)
    } catch {
        // catch error
    }
}

- wait

Keep the action.

Task {
    do {
        try await DroidOperator.default.go(at: 0.7)
        try await DroidOperator.default.wait(for: 2)
        try await DroidOperator.default.stop(.move)
    } catch {
        // catch error
    }
}

Swift Package Manager

Add the following dependency to your Package.swift file:

.package(url: "https://github.com/crane-hiromu/DroidKit", "2.2.2"..<"3.0.0")

License

MIT, of course ;-) See the LICENSE file.