Merge branch 'SimpleIosController' into 'master'

Simple ios controller

See merge request vato007/picar!1
This commit is contained in:
Michael Pivato
2020-05-06 12:17:59 +00:00
10 changed files with 181 additions and 29 deletions

4
.vscode/launch.json vendored
View File

@@ -10,9 +10,9 @@
"request": "launch",
"module": "car",
"env": {
"CAR_LIDAR": "LIDAR_RPLIDAR",
"CAR_LIDAR": "LIDAR_MOCK",
"CAR_VEHICLE": "CAR_MOCK",
"LIDAR_DEVICE": "/dev/tty.usbserial-0001"
// "LIDAR_DEVICE": "/dev/tty.usbserial-0001"
}
},
{

View File

@@ -21,7 +21,9 @@
5A9EB280240100970053D3CF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A9EB27F240100970053D3CF /* Assets.xcassets */; };
5A9EB283240100970053D3CF /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A9EB282240100970053D3CF /* Preview Assets.xcassets */; };
5A9EB286240100970053D3CF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A9EB284240100970053D3CF /* LaunchScreen.storyboard */; };
5AE45131245CFF2800D82BAF /* BuildFile in Frameworks */ = {isa = PBXBuildFile; productRef = 5AE45130245CFF2800D82BAF /* SwiftPackageProductDependency */; };
5AC1297B245EF22700CC19C3 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5AC1297A245EF22700CC19C3 /* Settings.bundle */; };
5AC1297D245FB95000CC19C3 /* PiLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AC1297C245FB95000CC19C3 /* PiLoader.swift */; };
5AE45131245CFF2800D82BAF /* GRPC in Frameworks */ = {isa = PBXBuildFile; productRef = 5AE45130245CFF2800D82BAF /* GRPC */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -41,6 +43,8 @@
5A9EB282240100970053D3CF /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
5A9EB285240100970053D3CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
5A9EB287240100970053D3CF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5AC1297A245EF22700CC19C3 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
5AC1297C245FB95000CC19C3 /* PiLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiLoader.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -48,7 +52,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5AE45131245CFF2800D82BAF /* BuildFile in Frameworks */,
5AE45131245CFF2800D82BAF /* GRPC in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -122,6 +126,8 @@
5A9EB281240100970053D3CF /* Preview Content */,
5A9C27122443F52500DBDF12 /* SimpleControllerView.swift */,
5A9C27142443F5B500DBDF12 /* ServerData.swift */,
5AC1297A245EF22700CC19C3 /* Settings.bundle */,
5AC1297C245FB95000CC19C3 /* PiLoader.swift */,
);
path = CarController;
sourceTree = "<group>";
@@ -151,7 +157,7 @@
);
name = CarController;
packageProductDependencies = (
5AE45130245CFF2800D82BAF /* SwiftPackageProductDependency */,
5AE45130245CFF2800D82BAF /* GRPC */,
);
productName = CarController;
productReference = 5A9EB276240100960053D3CF /* CarController.app */;
@@ -182,7 +188,7 @@
);
mainGroup = 5A9EB26D240100950053D3CF;
packageReferences = (
5AE4512F245CFF2800D82BAF /* RemoteSwiftPackageReference */,
5AE4512F245CFF2800D82BAF /* XCRemoteSwiftPackageReference "grpc-swift" */,
);
productRefGroup = 5A9EB277240100960053D3CF /* Products */;
projectDirPath = "";
@@ -198,6 +204,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5AC1297B245EF22700CC19C3 /* Settings.bundle in Resources */,
5A9EB286240100970053D3CF /* LaunchScreen.storyboard in Resources */,
5A9EB283240100970053D3CF /* Preview Assets.xcassets in Resources */,
5A9EB280240100970053D3CF /* Assets.xcassets in Resources */,
@@ -216,6 +223,7 @@
5A6B34552459AFCE0000E6FC /* SlamController.grpc.swift in Sources */,
5A6B34562459AFCE0000E6FC /* SlamController.pb.swift in Sources */,
5A6B34592459AFCE0000E6FC /* motorService.grpc.swift in Sources */,
5AC1297D245FB95000CC19C3 /* PiLoader.swift in Sources */,
5A9EB27A240100960053D3CF /* AppDelegate.swift in Sources */,
5A6B345A2459AFCE0000E6FC /* motorService.pb.swift in Sources */,
5A6B34582459AFCE0000E6FC /* lidar_tracker.grpc.swift in Sources */,
@@ -417,7 +425,7 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
5AE4512F245CFF2800D82BAF /* RemoteSwiftPackageReference */ = {
5AE4512F245CFF2800D82BAF /* XCRemoteSwiftPackageReference "grpc-swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/grpc/grpc-swift.git";
requirement = {
@@ -428,9 +436,9 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
5AE45130245CFF2800D82BAF /* SwiftPackageProductDependency */ = {
5AE45130245CFF2800D82BAF /* GRPC */ = {
isa = XCSwiftPackageProductDependency;
package = 5AE4512F245CFF2800D82BAF /* RemoteSwiftPackageReference */;
package = 5AE4512F245CFF2800D82BAF /* XCRemoteSwiftPackageReference "grpc-swift" */;
productName = GRPC;
};
/* End XCSwiftPackageProductDependency section */

View File

@@ -24,8 +24,8 @@
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
"revision": "e876fb37410e0036b98b5361bb18e6854739572b",
"version": "2.16.0"
"revision": "40bdad80882d307abe2c0bb36cf3bd4d3e03fe04",
"version": "2.16.1"
}
},
{

View File

@@ -15,16 +15,26 @@ struct ContentView: View {
NavigationLink(destination: SimpleControllerView()){
Text("Simple Controller")
}
// TODO: Change these when other functionality is implemented
NavigationLink(destination: SimpleControllerView()){
Text("Gamepad controller")
}
NavigationLink(destination: SimpleControllerView()){
Text("SLAM Controller")
}
NavigationLink(destination: SimpleControllerView()){
Text("Tracking Controller")
Text("Lidar Tracking Controller")
}
NavigationLink(destination: SimpleControllerView()){
Text("Mono Camera Tracking Controller")
}
NavigationLink(destination: SimpleControllerView()){
Text("Hybrid Lidar Camera Tracking Controller")
}
}
.navigationBarTitle(Text("Controllers"))
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

View File

@@ -0,0 +1,75 @@
//
// PiLoader.swift
// CarController
//
// Created by Michael Pivato on 4/5/20.
// Copyright © 2020 Michael Pivato. All rights reserved.
//
import Foundation
import SwiftUI
import GRPC
import NIO
class PiLoader: ObservableObject {
// Find a cleaner way to handle these properties
@Published var throttle: Float = 0.5
@Published var steering: Float = 0.5
var stopped = false
func startUpdating(forPort port: Int, atHost host: String) {
DispatchQueue.global(qos: .background).async{
let group = PlatformSupport.makeEventLoopGroup(loopCount: 1)
defer {
try? group.syncShutdownGracefully()
}
let client = makeClient(port: port, host: host, group: group)
let options = CallOptions(timeout: .seconds(rounding: 10))
let call = client.stream_vehicle_2d(callOptions: options)
call.response.whenFailure { error in
print("Failed: \(error)")
self.stop()
}
call.status.whenComplete { _ in
print("Finished")
self.stop()
}
call.response.whenSuccess { summary in
print("Finished")
self.stop()
}
// Running in background. Do the update thread stuff.
while (!self.stopped){
call.sendMessage(self.createProto(), promise: nil)
Thread.sleep(forTimeInterval: 0.2)
}
}
}
func stop(){
stopped = true
}
func createProto() -> MotorControl_Vehicle2DRequest {
return .with{
$0.throttle = .with{
$0.throttle = self.throttle
}
$0.steering = .with{
$0.steering = self.steering
}
}
}
}
func makeClient(port: Int, host: String, group: EventLoopGroup) -> MotorControl_CarControlClient {
let channel = ClientConnection.insecure(group: group)
// TODO: Pass the host in based on the settings.
.connect(host: host, port: port)
return MotorControl_CarControlClient(channel: channel)
}

View File

@@ -8,19 +8,18 @@
import Foundation
struct UserKeys{
static let host = "host"
static let port = "port"
}
final class ServerData: ObservableObject{
// TODO: Find a way to save/represent this stuff in iOS settings (user can access via settings app).
// Then load the below values ar runtime, from settings.
@Published var port: Int = 50051
@Published var grpcPort: Int = 50050
@Published var host: String = "10.0.0.53"
@Published var host: String = UserDefaults.standard.string(forKey: UserKeys.host) ?? "10.0.0.53"
@Published var grpcPort: Int = UserDefaults.standard.integer(forKey: UserKeys.port)
func load(){
// Load the server values from settings, if they had been
// previously saved.
// Load the server values from settings, if they had been previously saved.
}
func save(){

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>StringsTable</key>
<string>Root</string>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Type</key>
<string>PSTextFieldSpecifier</string>
<key>Title</key>
<string>Host</string>
<key>Key</key>
<string>host</string>
<key>DefaultValue</key>
<string>10.0.0.53</string>
<key>KeyboardType</key>
<string>Alphabet</string>
<key>AutocapitalizationType</key>
<string>None</string>
<key>AutocorrectionType</key>
<string>No</string>
</dict>
<dict>
<key>Type</key>
<string>PSTextFieldSpecifier</string>
<key>Title</key>
<string>Port</string>
<key>Key</key>
<string>port</string>
<key>DefaultValue</key>
<string>50051</string>
<key>IsSecure</key>
<false/>
<key>KeyboardType</key>
<string>NumberPad</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -10,14 +10,33 @@ import SwiftUI
struct SimpleControllerView: View {
@EnvironmentObject var server: ServerData
@State var throttle: Float = 0
@State var steering: Float = 0
@ObservedObject var grpcController: PiLoader = PiLoader()
var body: some View {
HStack{
Text("Opened Simple Controller!")
Slider(value: $throttle)
Slider(value: $steering)
VStack (alignment: .trailing, spacing: 0){
Spacer()
HStack{
// Move this up a bit, due to being rotated.
Slider(value: self.$grpcController.throttle, in: 0...1){_ in
self.grpcController.throttle = 0.5
}
.offset(x: 200)
.frame(width: 300)
.rotationEffect(.degrees(270))
Spacer()
Slider(value: self.$grpcController.steering, in: 0...1){_ in
self.grpcController.steering = 0.5
}
.frame(width:300)
.offset(x: -50, y: -200)
.padding()
}
.onAppear(){
self.grpcController.startUpdating(forPort: self.server.grpcPort, atHost: self.server.host)
}
.onDisappear(){
self.grpcController.stop()
}
}
}
}

View File

@@ -12,5 +12,5 @@ dependencies {
task copySwiftCode(type: Copy, dependsOn: configurations.swift) {
// Copy python protobuf code from proto project.
from zipTree(configurations.swift.asPath)
into './CarController/CarController'
into './CarController'
}