From 9376bd70edb2f7caee844ec7368898413bc34939 Mon Sep 17 00:00:00 2001 From: Piv <18462828+Piv200@users.noreply.github.com> Date: Mon, 4 May 2020 22:40:22 +0930 Subject: [PATCH] Simple Controller UI/gRPC working --- .../CarController.xcodeproj/project.pbxproj | 22 +++-- CarControlleriOS/CarController/PiLoader.swift | 76 ++++++++++++++++++ .../CarController/ServerData.swift | 3 +- .../CarController/Settings.bundle/Root.plist | 61 ++++++++++++++ .../Settings.bundle/en.lproj/Root.strings | Bin 0 -> 546 bytes .../CarController/SimpleControllerView.swift | 22 ++--- CarControlleriOS/build.gradle | 2 +- 7 files changed, 167 insertions(+), 19 deletions(-) create mode 100644 CarControlleriOS/CarController/PiLoader.swift create mode 100644 CarControlleriOS/CarController/Settings.bundle/Root.plist create mode 100644 CarControlleriOS/CarController/Settings.bundle/en.lproj/Root.strings diff --git a/CarControlleriOS/CarController.xcodeproj/project.pbxproj b/CarControlleriOS/CarController.xcodeproj/project.pbxproj index ab9af95..bfa7185 100644 --- a/CarControlleriOS/CarController.xcodeproj/project.pbxproj +++ b/CarControlleriOS/CarController.xcodeproj/project.pbxproj @@ -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 = ""; }; 5A9EB285240100970053D3CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 5A9EB287240100970053D3CF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5AC1297A245EF22700CC19C3 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; + 5AC1297C245FB95000CC19C3 /* PiLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiLoader.swift; sourceTree = ""; }; /* 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 = ""; @@ -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 */ diff --git a/CarControlleriOS/CarController/PiLoader.swift b/CarControlleriOS/CarController/PiLoader.swift new file mode 100644 index 0000000..3e007dd --- /dev/null +++ b/CarControlleriOS/CarController/PiLoader.swift @@ -0,0 +1,76 @@ +// +// 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 + let port: Int = 50051 + var stopped = false + + func makeClient(port: Int, group: EventLoopGroup) -> MotorControl_CarControlClient { + let channel = ClientConnection.insecure(group: group) + // TODO: Pass the host in based on the settings. + .connect(host: "10.0.0.55", port: port) + + return MotorControl_CarControlClient(channel: channel) + } + + func startUpdating() { + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { + try? group.syncShutdownGracefully() + } + let client = makeClient(port: self.port, group: group) + let options = CallOptions(timeout: .seconds(rounding: 10)) + let call = client.stream_vehicle_2d(callOptions: options) + + call.response.whenFailure { error in + print("RecordRoute Failed: \(error)") + self.stop() + } + + call.status.whenComplete { _ in + print("Finished RecordRoute") + self.stop() + } + + call.response.whenSuccess { summary in + print("Finished") + self.stop() + } + + DispatchQueue.global(qos: .userInteractive).async{ + // 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 + } + } + } +} diff --git a/CarControlleriOS/CarController/ServerData.swift b/CarControlleriOS/CarController/ServerData.swift index 816144a..e23830e 100644 --- a/CarControlleriOS/CarController/ServerData.swift +++ b/CarControlleriOS/CarController/ServerData.swift @@ -10,8 +10,9 @@ import Foundation final class ServerData: ObservableObject{ - // TODO: Find a way to save/represent this stuff in iOS settings (user can access via settings app). + // TODO: Find a way to save/represent this stuff in iOS settings/preferences (user can access via settings app). // Then load the below values ar runtime, from settings. + // Ideally want to be able to open this settings page from within the app as well. @Published var port: Int = 50051 diff --git a/CarControlleriOS/CarController/Settings.bundle/Root.plist b/CarControlleriOS/CarController/Settings.bundle/Root.plist new file mode 100644 index 0000000..b1b6fea --- /dev/null +++ b/CarControlleriOS/CarController/Settings.bundle/Root.plist @@ -0,0 +1,61 @@ + + + + + StringsTable + Root + PreferenceSpecifiers + + + Type + PSGroupSpecifier + Title + Group + + + Type + PSTextFieldSpecifier + Title + Name + Key + name_preference + DefaultValue + + IsSecure + + KeyboardType + Alphabet + AutocapitalizationType + None + AutocorrectionType + No + + + Type + PSToggleSwitchSpecifier + Title + Enabled + Key + enabled_preference + DefaultValue + + + + Type + PSSliderSpecifier + Key + slider_preference + DefaultValue + 0.5 + MinimumValue + 0 + MaximumValue + 1 + MinimumValueImage + + MaximumValueImage + + + + + diff --git a/CarControlleriOS/CarController/Settings.bundle/en.lproj/Root.strings b/CarControlleriOS/CarController/Settings.bundle/en.lproj/Root.strings new file mode 100644 index 0000000000000000000000000000000000000000..8cd87b9d6b20c1fbf87bd4db3db267fca5ad4df9 GIT binary patch literal 546 zcmaixOHRW;5JYRuDMndFh#Ua1V1d}N;sVAV2TO?uC3a9aJn*VxFrY}tnon0(S66#J z-d9>G>6W!ur(SDqlp`9nn~*(m%iWnv?yq`Qfp6XbK1?+om~~#r)ZnhkYQU_VbfjuT zHNn`CX<0sd*m1A}>&5sU$akD=GTXJ1e literal 0 HcmV?d00001 diff --git a/CarControlleriOS/CarController/SimpleControllerView.swift b/CarControlleriOS/CarController/SimpleControllerView.swift index da685a3..ee5188f 100644 --- a/CarControlleriOS/CarController/SimpleControllerView.swift +++ b/CarControlleriOS/CarController/SimpleControllerView.swift @@ -10,25 +10,27 @@ import SwiftUI struct SimpleControllerView: View { @EnvironmentObject var server: ServerData - @State var throttle: Float = 0.5 - @State var steering: Float = 0.5 - + + // Need lazy so that we can initialise with local properties. + @ObservedObject var grpcController: PiLoader = PiLoader() var body: some View { HStack{ - Slider(value: $throttle, in: 0...1){_ in - self.throttle = 0.5} + Slider(value: $grpcController.throttle, in: 0...1){_ in + self.grpcController.throttle = 0.5 + } .rotationEffect(.degrees(270)) - - Slider(value: $steering, in: 0...1){ - _ in self.steering = 0.5 + + Slider(value: $grpcController.steering, in: 0...1){_ in + self.grpcController.steering = 0.5 } } .onAppear(){ - // Start the gRPC updater. Should be in a separate class/struct to be easier to implement for SLAM Controller after. + self.grpcController.startUpdating() } .onDisappear(){ - + // Stop the gRPC updater. + self.grpcController.stop() } } } diff --git a/CarControlleriOS/build.gradle b/CarControlleriOS/build.gradle index ea6f5da..039b69b 100644 --- a/CarControlleriOS/build.gradle +++ b/CarControlleriOS/build.gradle @@ -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' } \ No newline at end of file