Skip to content

Commit

Permalink
Added rotation manager, Motion Research VC
Browse files Browse the repository at this point in the history
Motion research VC sends rotation data to Blender script
  • Loading branch information
JohnCoates committed Apr 15, 2018
1 parent a5976aa commit 34e89b2
Show file tree
Hide file tree
Showing 8 changed files with 716 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ UINavigationControllerDelegate, NavigationConvenience {
self.kitsTab(),
self.database(),
self.vectors(),
self.buttons()
self.buttons(),
self.research()
]
}()

Expand Down Expand Up @@ -292,6 +293,15 @@ UINavigationControllerDelegate, NavigationConvenience {
return Section(title: "Vector Images", items: items)
}

func research() -> Section {
let items: [FeatureCatalogItem] = [
FeatureCatalogItem(name: "Send Motion Data",
creationBlock: { MotionSendViewController() })
]

return Section(title: "Research", items: items)
}

// MARK: - Navigation Swipe Back

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
//
// MotionSendViewController
// Created on 4/14/18.
// Copyright © 2018 John Coates. All rights reserved.
//

import UIKit
import CFNetwork
import CoreMotion

class MotionSendViewController: UIViewController, StreamDelegate,
NetServiceBrowserDelegate, NetServiceDelegate {

// MARK: - View Management

override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
setUpButton()
setUpStackView()
start()
}

// MARK: - View Events

override func viewWillAppear(_ animated: Bool) {
super.viewDidAppear(animated)
start()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewDidAppear(animated)
stop()
}

let button = UIButton(type: .custom)
private func setUpButton() {

button.setTitle("Restart", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
button.setTitleColor(.black, for: .normal)
view.addSubview(button)
button.centerXY --> view
}

let pitchLabel = UILabel()
let yawLabel = UILabel()
let rollLabel = UILabel()
let orientationLabel = UILabel()
private func setUpStackView() {
let stackView = UIStackView(arrangedSubviews: [
pitchLabel,
yawLabel,
rollLabel,
orientationLabel
])
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.spacing = 15
stackView.alignment = .leading
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 10, left: 10,
bottom: 10, right: 10)

view.addSubview(stackView)

stackView.bottom.pin(to: button.top, add: -15)
}

// MARK: - Start, Stop

var orientation: UIInterfaceOrientation = .unknown

func start() {
RotationManager.updateInterval = 0.01
RotationManager.shared.attitudeUpdated = { attitude in
var motionData = MotionData()

DispatchQueue.main.async {
self.updateLabels(with: attitude)
}

let quaternion = attitude.quaternion
motionData.x = quaternion.x
motionData.y = quaternion.y
motionData.z = quaternion.z
motionData.w = quaternion.w
let encoder = JSONEncoder()
do {
let json = try encoder.encode(motionData)
self.send(data: json)
} catch let error {
print("Couldn't send data, error: \(error)")
}
}

if let host = hostAddress {
setUpStreams(host: host)
} else {
searchForHost()
}

RotationManager.beginOrientationEvents()
}

func updateLabels(with attitude: CMAttitude) {
let pitch = RotationManager.degrees(radians: attitude.pitch)
let yaw = RotationManager.degrees(radians: attitude.yaw)
let roll = RotationManager.degrees(radians: attitude.roll)
pitchLabel.text = "pitch: \(pitch)"
yawLabel.text = "yaw: \(yaw)"
rollLabel.text = "roll: \(roll)"
orientation = RotationManager.newOrientation(from: self.orientation,
pitch: pitch,
yaw: yaw,
roll: roll)
orientationLabel.text = self.orientation.description
}

func stop() {
RotationManager.endOrientationEvents()
inputStream?.close()
outputStream?.close()
inputStream = nil
outputStream = nil
}

// MARK: - Streams

var inputStream: InputStream?
var outputStream: OutputStream?

func setUpStreams(host: String) {
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
host as CFString, 9845,
&readStream,
&writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
guard let inputStream = inputStream, let outputStream = outputStream else {
print("Failed to create streams")
return
}
inputStream.delegate = self
outputStream.delegate = self
inputStream.schedule(in: .current, forMode: .commonModes)
outputStream.schedule(in: .current, forMode: .commonModes)
inputStream.open()
outputStream.open()
}

func send(data: Data) {
guard let outputStream = outputStream else {
return
}
_ = data.withUnsafeBytes {
outputStream.write($0, maxLength: data.count)
}
}

let maxReadLength = 4096

public func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
if eventCode == .errorOccurred {
inputStream = nil
outputStream = nil
print("Error: Stream error")
} else if eventCode == .endEncountered {
inputStream = nil
outputStream = nil
print("Error: Encountered end of stream")
}

if eventCode == .hasBytesAvailable {
guard let inputStream = inputStream else {
return
}
while inputStream.hasBytesAvailable {
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxReadLength)
inputStream.read(buffer, maxLength: maxReadLength)
buffer.deallocate()
}
}
}

// MARK: - User Interaction

@objc func buttonTapped() {
stop()
start()
}

// MARK: - Bonjour

private let browser = NetServiceBrowser()
var searching = false
func searchForHost() {
guard searching == false else {
return
}
searching = true
print("searching for host")
browser.delegate = self
browser.searchForServices(ofType: "_companion-link._tcp", inDomain: "local.")
}

private var hostService: NetService?
private var hostAddress: String?

func netServiceBrowser(_ browser: NetServiceBrowser,
didFind service: NetService, moreComing: Bool) {
print("found service: \(service)")
service.delegate = self
service.resolve(withTimeout: 20)
hostService = service
browser.stop()
}

func netServiceDidResolveAddress(_ sender: NetService) {
guard let addresses = sender.addresses else {
return
}

for addressData in addresses {
let addressPointer = addressData.withUnsafeBytes { (pointer: UnsafePointer<sockaddr_in>) in
return pointer
}
let rawAddress = addressPointer.pointee

// IPv4 only
guard rawAddress.sin_family == AF_INET else {
continue
}
var host = [CChar](repeating: 0, count: Int(NI_MAXHOST))
let result = addressData.withUnsafeBytes { (sockAddress: UnsafePointer<sockaddr>) in
getnameinfo(sockAddress, socklen_t(addressData.count), &host,
socklen_t(host.count), nil, 0, NI_NUMERICHOST)

}
guard result == 0 else {
return
}
guard hostAddress == nil else {
return
}
let address = String(cString: host)
hostAddress = address
print("found host address: \(address)")
setUpStreams(host: address)
}

}

}

// MARK: - Models

private struct MotionData: Codable {
var x: Double = 0
var y: Double = 0
var z: Double = 0
var w: Double = 0
}
6 changes: 6 additions & 0 deletions Research/Motion/Blender/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import socket

send = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
send.connect(("localhost", 9845))
send.send("{ \"x\": 1.2, \"y\": 0, \"z\": 1.2, \"w\": 0}")
send.close()
Loading

2 comments on commit 34e89b2

@JohnCoates
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, forgot to mention that this commit also adds correct rotation for photos

@saygoletsgo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still do not know how to send data from iPhone to MAC

Please sign in to comment.