Depend on external car wrapper library
This commit is contained in:
@@ -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/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://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/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: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// 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.
|
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
|
||||||
.target(
|
.target(
|
||||||
name: "SwiftyCar",
|
name: "SwiftyCar",
|
||||||
dependencies: ["SwiftyGPIO", .product(name: "GRPC", package: "grpc-swift"), "SwiftRPLidar"]),
|
dependencies: ["SwiftyGPIO", .product(name: "GRPC", package: "grpc-swift"), "SwiftRPLidar", "Swift2dCar"]),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "SwiftyCarTests",
|
name: "SwiftyCarTests",
|
||||||
dependencies: ["SwiftyCar"]),
|
dependencies: ["SwiftyCar"]),
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,60 +6,47 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftyGPIO
|
import Swift2dCar
|
||||||
|
|
||||||
protocol Vehicle{
|
public typealias ThrottleHandler = (_ magnitude: Float) -> Float
|
||||||
mutating func move2D(magnitude: Float, angle: Float)
|
public typealias SteeringHandler = (_ angle: Float) -> Float
|
||||||
}
|
|
||||||
|
|
||||||
protocol Vehicle2D: Vehicle{
|
|
||||||
var throttle: Float {get set}
|
|
||||||
var steering: Float {get set}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MockVehicle: Vehicle2D{
|
public class IntelligentPiCar : RPiVehicle2D {
|
||||||
var throttle: Float = 0
|
|
||||||
var steering: Float = 0
|
|
||||||
|
|
||||||
|
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) {
|
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user