Initial Commit

This commit is contained in:
Piv
2020-08-31 22:47:00 +09:30
commit 2777d5c48d
9 changed files with 252 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/

6
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,6 @@
image: vato.ddns.net:8083/swift:5.2.4
build:
stage: build
script:
- swift build

27
Package.swift Normal file
View File

@@ -0,0 +1,27 @@
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Swift2dCar",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "Swift2dCar",
targets: ["Swift2dCar"]),
],
dependencies: [
.package(url: "https://github.com/uraimo/SwiftyGPIO.git", from: "1.2.5"),
],
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: "Swift2dCar",
dependencies: ["SwiftyGPIO"]),
.testTarget(
name: "Swift2dCarTests",
dependencies: ["Swift2dCar"]),
]
)

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Swift2dCar
A description of this package.

View File

@@ -0,0 +1,113 @@
//
// Servo.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
}
protocol Servo {
var value: Float {get set}
var minPulseWidth: Float {get}
var maxPulseWidth: Float {get}
var pulseWidth: Float {get}
func min()
func mid()
func max()
func detach()
}
public class PWMHardwareServo : 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 minDc * frameWidth
}
}
var maxPulseWidth: Float{
get{
return (dcRange * frameWidth) + minPulseWidth
}
}
var pulseWidth: Float{
get{
return internalValue * frameWidth
}
}
var value: Float{
get{
internalValue
}
set(newValue){
internalValue = newValue
device.startPWM(period: Int(frameWidth),
// Multiply by 100 to get into percentage. I don't like that...
duty: minDc + dcRange * ((internalValue - minValue) / valueRange) * 100)
}
}
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()
}
}

View File

@@ -0,0 +1,67 @@
//
// Vehicle.swift
//
//
// Created by Michael Pivato on 8/5/20.
//
import Foundation
import SwiftyGPIO
protocol Vehicle2D{
var throttle: Float {get set}
var steering: Float {get set}
mutating func move2D(magnitude: Float, angle: Float)
}
class MockVehicle: Vehicle2D {
var throttle: Float = 0
var steering: Float = 0
func move2D(magnitude: Float, angle: Float) {
}
}
class RPiVehicle2D: Vehicle2D{
public var pwmThrottle: Servo
public var 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 calibrate(){
// Define a function that indicates how the throttle/steering should be set for given magnitude/angle to move.
}
func move2D(magnitude: Float, angle: Float) {
}
func stop(){
pwmThrottle.detach()
pwmSteering.detach()
}
}

7
Tests/LinuxMain.swift Normal file
View File

@@ -0,0 +1,7 @@
import XCTest
import Swift2dCarTests
var tests = [XCTestCaseEntry]()
tests += Swift2dCarTests.allTests()
XCTMain(tests)

View File

@@ -0,0 +1,15 @@
import XCTest
@testable import Swift2dCar
final class Swift2dCarTests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
// XCTAssertEqual(Swift2dCar().text, "Hello, World!")
}
static var allTests = [
("testExample", testExample),
]
}

View File

@@ -0,0 +1,9 @@
import XCTest
#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(Swift2dCarTests.allTests),
]
}
#endif