diff --git a/SwiftyCar/Package.swift b/SwiftyCar/Package.swift index a46de07..4f104bf 100644 --- a/SwiftyCar/Package.swift +++ b/SwiftyCar/Package.swift @@ -14,14 +14,15 @@ let package = Package( .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.12"), .package(url: "https://github.com/uraimo/SwiftyGPIO.git", from: "1.0.0"), .package(url: "https://vato.ddns.net/gitlab/vato007/swiftrplidar.git", .branch("master")), - .package(url: "https://vato.ddns.net/gitlab/vato007/SwiftSerial.git", .branch("dtr_support")) + .package(url: "https://vato.ddns.net/gitlab/vato007/SwiftSerial.git", .branch("dtr_support")), + .package(url: "https://vato.ddns.net/gitlab/vato007/swift2dcar.git", .branch("master")) ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "SwiftyCar", - dependencies: ["SwiftyGPIO", .product(name: "GRPC", package: "grpc-swift"), "SwiftRPLidar"]), + dependencies: ["SwiftyGPIO", .product(name: "GRPC", package: "grpc-swift"), "SwiftRPLidar", "Swift2dCar"]), .testTarget( name: "SwiftyCarTests", dependencies: ["SwiftyCar"]), diff --git a/SwiftyCar/Sources/SwiftyCar/PwmWrappers.swift b/SwiftyCar/Sources/SwiftyCar/PwmWrappers.swift deleted file mode 100644 index 688351e..0000000 --- a/SwiftyCar/Sources/SwiftyCar/PwmWrappers.swift +++ /dev/null @@ -1,104 +0,0 @@ -// -// PwmWrappers.swift -// -// Simple wrappers for PwmOutput I'll create as I go along, to match gpioZero's implementation I'm currently using. -// See gpiozero code here: https://github.com/gpiozero/gpiozero/blob/master/gpiozero/output_devices.py -// -// Created by Michael Pivato on 9/5/20. -// - -import Foundation -import SwiftyGPIO - -enum ServoError: Error{ - case invalidMinPulseWidth - case invalidMaxPulseWidth -} - -class Servo{ - private (set) var frameWidth : Float - private var minDc: Float - private var dcRange: Float - private var minValue: Float - private var valueRange: Float - private var internalValue: Float - - // TODO: Use a factory to provide the correct pwm rather than passing the pin in. - private var device: PWMOutput - private var currentPulseWIdth: Float - - var minPulseWidth: Float { - get{ - return self.minDc * self.frameWidth - } - } - - var maxPulseWidth: Float{ - get{ - return (self.dcRange * self.frameWidth) + self.minPulseWidth - } - } - - // TODO: Also store the pulse width (needs to be within this class) - // var pulseWidth: Float{ - // get{ - // return self.device//self.pwm_device.pin.state * self.frame_width - // } - // set (value){ - // - // } - // } - - var value: Float{ - get{ - internalValue - } - set(newValue){ - self.internalValue = newValue - self.device.startPWM(period: Int(self.frameWidth), - // Multiple by 100 to get into percentage. I don't like that... - duty: self.minDc + self.dcRange * ((internalValue - self.minValue) / self.valueRange) * 100) - } - } - - // TODO: Change this to nanoseconds to match PWMOutput - init?(forPin pin: PWMOutput, startingAt initialValue: Float = 0, withMinPulseWidth minPulseWidth: Float = 1000000, - withMaxPulseWidth maxPulseWidth: Float = 2000000, withFrameWidth frameWidth: Float = 20000000) throws { - if(minPulseWidth >= maxPulseWidth){ - throw ServoError.invalidMinPulseWidth - } - - if(maxPulseWidth >= frameWidth){ - throw ServoError.invalidMaxPulseWidth - } - self.frameWidth = frameWidth - self.minDc = minPulseWidth / frameWidth - self.dcRange = (maxPulseWidth - minPulseWidth) / frameWidth - self.minValue = -1 - self.valueRange = 2 - - self.currentPulseWIdth = 0 - - // Initialise pin immediately. - self.device = pin - self.device.initPWM() - self.internalValue = initialValue - self.device.startPWM(period: Int(self.frameWidth), duty: self.minDc + self.dcRange * ((internalValue - self.minValue) / self.valueRange) * 100) - } - - func min(){ - self.value = -1 - } - - func mid(){ - self.value = 0 - } - - func max() { - self.value = 1 - } - - func detach(){ - self.device.stopPWM() - } -} diff --git a/SwiftyCar/Sources/SwiftyCar/Vehicle.swift b/SwiftyCar/Sources/SwiftyCar/Vehicle.swift index 957bc15..ab617c1 100644 --- a/SwiftyCar/Sources/SwiftyCar/Vehicle.swift +++ b/SwiftyCar/Sources/SwiftyCar/Vehicle.swift @@ -6,60 +6,47 @@ // import Foundation -import SwiftyGPIO +import Swift2dCar -protocol Vehicle{ - mutating func move2D(magnitude: Float, angle: Float) -} +public typealias ThrottleHandler = (_ magnitude: Float) -> Float +public typealias SteeringHandler = (_ angle: Float) -> Float -protocol Vehicle2D: Vehicle{ - var throttle: Float {get set} - var steering: Float {get set} -} -class MockVehicle: Vehicle2D{ - var throttle: Float = 0 - var steering: Float = 0 +public class IntelligentPiCar : RPiVehicle2D { + private var vehicleLength: Float? + private var throttleFunc: ThrottleHandler? + private var steeringFunc: SteeringHandler? + + /**: + Calibration function for how the car moves (acoording to a bicycle model) for a given throttle/steering angle. This sets the way the + - Parameters + - carLength + */ + func calibrate(vehicleLength: Float, throttleFunc: @escaping ThrottleHandler, steeringFunc: @escaping SteeringHandler){ + // Define a function that indicates how the throttle/steering should be set for given magnitude/angle to move. + self.vehicleLength = vehicleLength + self.throttleFunc = throttleFunc + self.steeringFunc = steeringFunc + } + + /** + Move the car by the given magnitude and angle, depending on how the is known to move with apriori throttle/steering. + */ func move2D(magnitude: Float, angle: Float) { + if let throttleFunc = self.throttleFunc { + self.pwmThrottle.value = throttleFunc(magnitude) + } + if let steeringFunc = steeringFunc { + self.pwmSteering.value = steeringFunc(angle) + } + } + + /** + Move to the coordinates relative to the car. You must first calibrate the car. A bicycle model is assumed. + */ + func moveRelativeTo2D(x: Float, y: Float) { + // TODO: This function, has a lot of edge cases. Also is really } } - -class RPiVehicle2D: Vehicle2D{ - public let pwmThrottle: Servo - public let pwmSteering: Servo - - var throttle: Float{ - get{ - return pwmThrottle.value - } - set(value){ - pwmThrottle.value = value - } - } - - var steering: Float{ - get{ - return pwmSteering.value - } - set(value){ - pwmSteering.value = value - } - } - - init(withThrottlePin: Servo, withSteeringPin: Servo){ - pwmThrottle = withThrottlePin - pwmSteering = withSteeringPin - } - - func move2D(magnitude: Float, angle: Float) { - - } - - func stop(){ - pwmThrottle.detach() - pwmSteering.detach() - } - -}