iPhone Accelerometer forward,back,left,right - ios

I would like to know how to create code that would allow me to place an iPhone flat on a surface and move it forward to get positive y value, back to get -y, left to get -x and right to get -x. The code I am using only seems to measure positive acceleration and I can not generate negative values while the phone is laid flat on surface. If I lift the phone and then tilt it to the right or left, I will get positive x and negative x and same with y but I want the same affect while leaving it on the surface and simply shifting the phone in left and right directions while keeping it facing forward without any type of turning or rotation. I am using swift but will also be happy to use object c if there is a solution.
import UIKit
import CoreMotion
class ViewController: UIViewController {
var currentMaxAccelX: Double = 0.0
var currentMaxAccelY: Double = 0.0
var currentMaxAccelZ: Double = 0.0
let motionManager = CMMotionManager()
#IBOutlet var accX : UILabel? = nil
#IBOutlet var accY : UILabel? = nil
#IBOutlet var accZ : UILabel? = nil
#IBOutlet var maxAccX : UILabel? = nil
#IBOutlet var maxAccY : UILabel? = nil
#IBOutlet var maxAccZ : UILabel? = nil
override func viewDidLoad() {
super.viewDidLoad()
motionManager.accelerometerUpdateInterval = 0.1
//[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue new] withHandler:^(CMDeviceMotion *motion, NSError *error)
motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.currentQueue(), withHandler: {(accelerometerData: CMAccelerometerData!, error:NSError!)in
self.outputAccelerationData(accelerometerData.acceleration)
if (error != nil)
{
println("\(error)")
}
})
}
func outputAccelerationData(acceleration:CMAcceleration)
{
// Swift does not have string formation yet
accX?.text = NSString(format:"%.4f", acceleration.x) as String
if fabs(acceleration.x) > fabs(currentMaxAccelX)
{
currentMaxAccelX = acceleration.x
}
accY?.text = NSString(format:"%.4f", acceleration.y) as String
if acceleration.y > currentMaxAccelY
{
currentMaxAccelY = acceleration.y
}
accZ?.text = NSString(format:"%.4f", acceleration.z) as String
if acceleration.z > currentMaxAccelZ
{
currentMaxAccelZ = acceleration.z
}
maxAccX?.text = NSString(format:"%.4f", currentMaxAccelX) as String
maxAccY?.text = NSString(format:"%.4f", currentMaxAccelY) as String
maxAccZ?.text = NSString(format:"%.4f", currentMaxAccelZ) as String
}

Related

How can I combine all 3 gyroscope axis to produce 1 int? Xcode Swift Core Motion

I've followed a few things including Apple's documentation on the core motion. This is probably very simple to do, I just can't put my finger on it. Basically, I'm trying to get all of the X, Y, and Z data, combine it and make it constantly add to the "scoreValue" text. Basically, a constant counter that counts the total degrees rotated ever.
import UIKit
import CoreMotion
class ViewController: UIViewController {
#IBOutlet var scoreValue: UITextView!
#IBOutlet weak var Label: UILabel!
var motion = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
myGyroscope()
view.backgroundColor = .systemBlue
}
func myGyroscope() {
motion.gyroUpdateInterval = 0.1
motion.startGyroUpdates(to: OperationQueue.current!) { [self]
(data, error) in
print(data as Any)
if let trueData = data {
self.view.reloadInputViews()
let x = trueData.rotationRate.x
let y = trueData.rotationRate.y
let z = trueData.rotationRate.z
self.UNDEFINED.text = "\(Double(x).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(y).rounded(toPlaces :0))"
self.UNDEFINED.text = "\(Double(z).rounded(toPlaces :0))"
}
}
return
}
}
extension Double {
/// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

stuck either calculating correctly, or with code that crashes

I'm fighting the problem of either having correct calculations (that's awesome) but crashes if I leave a text field blank in the simulator (not awesome) OR: when coded differently, no crashes for blank text fields (not good) but calculates incorrectly (not good).
here's what I'm trying to do:
get user input for 4 values: fibers counted, blank fibers counted (ok if it's zero), fields counted, and sample volume. I put in defaults hoping to take care of any instances where text boxes are blank, hoping to prevent crashes. then the app calculates fiber density, limit of detection, and sample result. pretty simple for now but I hope to add to this later.
My main problem has been optionals. I've read up on that and done my best to code correctly, but there are times when Xcode forces me into a corner. So my app crashes when text fields are blank. or I can prevent crashes but somehow the default values will get used in the calculations and the actual data is off.
I must be using if-let incorrectly, so I tried what you see in the code below.
I'll put the code below, and as always, thanks for any help, and understanding that I'm new and trying to get these concepts down while being self-taught (besides lessons learned here). Thanks!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var fibersCountedTextField: UITextField!
#IBOutlet weak var blankFibersCountedTextField: UITextField!
#IBOutlet weak var fieldsCountedTextField: UITextField!
#IBOutlet weak var sampleVolumeTextField: UITextField!
#IBOutlet weak var fiberDensityLabel: UILabel!
#IBOutlet weak var limitOfDetectionLabel: UILabel!
#IBOutlet weak var sampleResultLabel: UILabel!
#IBAction func calculateBtnPressed(_ sender: Any) {
var blankCheck: String?
var blankFibersCounted: Double?
var fibersCheck: String?
var fibersCounted: Double?
var fieldsCheck: String?
var fieldsCounted: Double?
var volumeCheck: String?
var sampleVolume: Double?
var sampleResultNumerator: Double?
var sampleResultDenominator: Double?
var sampleResult: Double?
var sampleResultRounded: Double
var fiberDensity: Double
var fiberDensityRounded: Double
var limitOfDetectionNumerator: Double
var limitOfDetectionDenominator: Double
var sampleLimitOfDetection: Double
var sampleLimitOfDetectionRounded: Double
struct TypicalSampleData {
let typicalBlankFibersCounted: Double
let typicalFibersCounted: Double
let typicalFieldsCounted: Double
let typicalSampleVolume: Double
init(typicalBlankFibersCounted: Double = 4.0, typicalFibersCounted: Double = 5.5, typicalFieldsCounted: Double = 100.0, typicalSampleVolume: Double = 555.0) {
self.typicalBlankFibersCounted = typicalBlankFibersCounted
self.typicalFibersCounted = typicalFibersCounted
self.typicalFieldsCounted = typicalFieldsCounted
self.typicalSampleVolume = typicalSampleVolume
}
}
//this code calculates correctly but crashes if text boxes left empty in the simulator.
let defaultSampleData = TypicalSampleData()
//if let blankCheck = blankFibersCountedTextField.text {
// blankFibersCounted = Double(blankCheck)
//} else {
// blankFibersCounted = defaultSampleData.typicalBlankFibersCounted
//}
//blankCheck = blankFibersCountedTextField.text
//var blankCheckDbl: Double?
//if let blankCheck = blankFibersCountedTextField.text {
// blankFibersCounted = Double(blankCheck)
//}; blankFibersCounted = defaultSampleData.typicalBlankFibersCounted
//if let fibersCheck = fibersCountedTextField.text {
// fibersCounted = Double(fibersCheck)
//} else {
// fibersCounted = defaultSampleData.typicalFibersCounted
//}
if blankFibersCountedTextField != nil {
blankCheck = blankFibersCountedTextField.text
} else {
blankFibersCounted = defaultSampleData.typicalBlankFibersCounted
}
if blankCheck == blankFibersCountedTextField.text {
blankFibersCounted = Double(blankCheck!)
} else {
blankFibersCounted = defaultSampleData.typicalBlankFibersCounted
}
if fibersCountedTextField != nil {
fibersCheck = fibersCountedTextField.text
} else {
fibersCounted = defaultSampleData.typicalFibersCounted
}
if fibersCheck == fibersCountedTextField.text {
fibersCounted = Double(fibersCheck!)
} else {
fibersCounted = defaultSampleData.typicalFibersCounted
}
if fieldsCountedTextField != nil {
fieldsCheck = fieldsCountedTextField.text
} else {
fieldsCounted = defaultSampleData.typicalFieldsCounted
}
if fieldsCheck == fieldsCountedTextField.text {
fieldsCounted = Double(fieldsCheck!)
} else {
fieldsCounted = defaultSampleData.typicalFieldsCounted
}
if sampleVolumeTextField != nil {
volumeCheck = sampleVolumeTextField.text
} else {
sampleVolume = defaultSampleData.typicalSampleVolume
}
if volumeCheck == sampleVolumeTextField.text {
sampleVolume = Double(volumeCheck!)
} else {
sampleVolume = defaultSampleData.typicalSampleVolume
}
//if let fibersCheck = fibersCountedTextField.text {
// fibersCounted = Double(fibersCheck)
//}; fibersCounted = defaultSampleData.typicalFibersCounted
//if let fieldsCheck = fieldsCountedTextField.text {
// fieldsCounted = Double(fieldsCheck)
//} else {
// fieldsCounted = defaultSampleData.typicalFieldsCounted
//}
//if let fieldsCheck = fieldsCountedTextField.text {
// fieldsCounted = Double(fieldsCheck)
//}; fieldsCounted = defaultSampleData.typicalFieldsCounted
//if let volumeCheck = sampleVolumeTextField.text {
// sampleVolume = Double(volumeCheck)
//} else {
// sampleVolume = defaultSampleData.typicalSampleVolume
//}
//if let volumeCheck = sampleVolumeTextField.text {
// sampleVolume = Double(volumeCheck)
//}; sampleVolume = defaultSampleData.typicalSampleVolume
//calculate result
if let fibersCounted = fibersCounted, fibersCounted < 5.5 {
sampleResultNumerator = (385 * (5.5 / 100))
sampleResultDenominator = (7.85 * sampleVolume!)
sampleResult = sampleResultNumerator! / sampleResultDenominator!
} else {
sampleResultNumerator = 385 * ((fibersCounted! - blankFibersCounted!) / fieldsCounted!)
sampleResultDenominator = (7.85 * sampleVolume!)
sampleResult = sampleResultNumerator! / sampleResultDenominator!
}
sampleResultRounded = Double(round(1000 * sampleResult!)/1000)
//calculate sample limit of detection
//insert if-let statement here, similar to above?
limitOfDetectionNumerator = 385 * (5.5 / 100)
limitOfDetectionDenominator = (7.85 * sampleVolume!)
sampleLimitOfDetection = limitOfDetectionNumerator / limitOfDetectionDenominator
sampleLimitOfDetectionRounded = Double(round(1000 * sampleLimitOfDetection)/1000)
//calculate fiber density
//insert if-let statement here, similar to above?
fiberDensity = ((fibersCounted! - blankFibersCounted!) / fieldsCounted!) / 0.00785
fiberDensityRounded = Double(round(1000 * fiberDensity)/1000)
fiberDensityLabel.text = String(fiberDensityRounded)
limitOfDetectionLabel.text = String(sampleLimitOfDetectionRounded)
sampleResultLabel.text = String(sampleResultRounded)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
There are various ways to approach your task, but here is a very straight-forward method (replace fieldA, fieldB, etc with your actual #IBOutlet names):
#IBAction func calculateBtnPressed(_ sender: Any) {
let defaultSampleData = TypicalSampleData()
// get the text from fieldA - set it to "" if fieldA.text is nil
let textA = fieldA.text ?? ""
// get the text from fieldB - set it to "" if fieldB.text is nil
let textB = fieldB.text ?? ""
// if textA CAN be converted to a Double, use it, otherwise use default value
let valA = Double(textA) ?? defaultSampleData.typicalBlankFibersCounted
// if textB CAN be converted to a Double, use it, otherwise use default value
let valB = Double(textB) ?? defaultSampleData.typicalFibersCounted
// set resultLabel.text to the product of valA and valB
resultLabel.text = "Result: \(valA * valB)"
}
The idea being: make sure you have default values for each part of your "equation".
Depending on your actual use-case, of course, you may want to display an Error popup message instead of using default values. But this should get you on your way.

New to coding and working an example in the book which was written for xcode 6.2 and I have the newest version.

I get the following error when I run the app and try and click any key on the keypad that opens on launch.
Here is the error I get in the attached photo
Below is my code and it highlights the first func at the bottom called func formatAsCurrancy... as the problem area. I have converted all the old code in the book as it prompted me to. Not sure what to do at this point. Thank you for any help.
import UIKit
class ViewController: UIViewController {
//properties for programmatically interacting with UI components
#IBOutlet weak var billAmountLabel: UILabel!
#IBOutlet weak var customTipPercentLabel1: UILabel!
#IBOutlet weak var customTipPercentageSlider: UISlider!
#IBOutlet weak var customTipPercentLabel2: UILabel!
#IBOutlet weak var tip15Label: UILabel!
#IBOutlet weak var total15Label: UILabel!
#IBOutlet weak var tipCustomLabel: UILabel!
#IBOutlet weak var totalCustomLabel: UILabel!
#IBOutlet weak var inputTextField: UITextField!
// NSDecimalNumber constants used in the calculateTip method
let decimal100 = NSDecimalNumber(string: "100.0")
let decimal15Percent = NSDecimalNumber(string: "0.15")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// select inputTextField so keypad displays when the view loads
inputTextField.becomeFirstResponder()
}
#IBAction func calculateTip(_ sender: Any) {
let inputString = inputTextField.text //get user input
// convert slider value to an NSDecimalNumber
let sliderValue =
NSDecimalNumber(integerLiteral: Int(customTipPercentageSlider.value))
// divide sliderValue by decimal100 (100.0) to get tip %
let customPercent = sliderValue / decimal100
// did customTipPercentageSlider generate the event?
if sender is UISlider {
// thumb moved so update the Labels with new custom percent
customTipPercentLabel1.text =
NumberFormatter.localizedString(from: customPercent,
number: NumberFormatter.Style.percent)
customTipPercentLabel2.text = customTipPercentLabel1.text
}
// if there is a bill amount, calculate tips and totals
if !(inputString?.isEmpty)! {
// convert to NSDecimalNumber and insert decimal point
let billAmount =
NSDecimalNumber(string: inputString) / decimal100
// did inputTextField generate the event?
if sender is UITextField {
billAmountLabel.text = " " + formatAsCurrency(number: billAmount)
// calculate and display the 15% tip and total
let fifteenTip = billAmount * decimal15Percent
tip15Label.text = formatAsCurrency(number: fifteenTip)
total15Label.text =
formatAsCurrency(number: billAmount + fifteenTip)
}
// calculate custom tip and display custom tip and total
let customTip = billAmount * customPercent
tipCustomLabel.text = formatAsCurrency(number: customTip)
totalCustomLabel.text =
formatAsCurrency(number: billAmount + customTip)
}
else {// clear all Labels
billAmountLabel.text = ""
tip15Label.text = ""
total15Label.text = ""
tipCustomLabel.text = ""
totalCustomLabel.text = ""
}
}
}
// convert a numeric value to localized currency string
func formatAsCurrency(number: NSNumber) -> String {
return NumberFormatter.localizedString(
from: number, number: NumberFormatter.Style.currency)
}
// overloaded + operator to add NSDecimalNumbers
func +(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.adding(right)
}
// overloaded * operator to multiply NSDecimalNumbers
func *(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.multiplying(by: right)
}
// overloaded / operator to divide NSDecimalNumbers
func /(left: NSDecimalNumber, right: NSDecimalNumber) -> NSDecimalNumber {
return left.dividing(by: right)
}
The simulator is trying to find a numeric keyboard on your computer, but your computer shouldn't have one so that's why it's giving you the error.
If you go to the simulator and then Hardware -> Keyboard -> Uncheck use hardware keyboard, the issue will go away.

UIDynamicAnimator - Move view based on Device Motion Roll

I am trying to read my devices Motion, specifically the Roll of the device when it is in Landscape Mode, and translate the angle returned into a Position of a UIView (Basically making a on screen "Level" to show the user that the phone is at an ideal angle).
This code gives the desired roll result, but for some reason is not updating the levelIndicator view as expected. I am not getting any errors, so I must be using UIPushBehavior incorrectly, but I am unclear what I need to fix. I am not sure about setting to new Y position of the indicator on Motion Update.
import UIKit
import AVFoundation
import CoreMotion
import GLKit
class CameraView: BaseViewController {
var animator : UIDynamicAnimator? = nil;
var currentRoll : Float = 0.0;
let manager = CMMotionManager()
let motionQueue = NSOperationQueue()
var countingDown:Bool = false;
#IBOutlet weak var levelIndicator: UIView!
#IBOutlet weak var level: UIView!
override func viewDidLoad() {
super.viewDidLoad()
self.animator = UIDynamicAnimator(referenceView: self.level)
let continuousPush: UIPushBehavior = UIPushBehavior(items: [levelIndicator], mode: UIPushBehaviorMode.Continuous)
self.animator?.addBehavior(continuousPush)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
self.startReadingMotion()
}
func startReadingMotion() {
if manager.deviceMotionAvailable {
manager.deviceMotionUpdateInterval = 0.1
manager.startDeviceMotionUpdatesToQueue(motionQueue, withHandler: checkStability)
}
}
func checkStability(motion: CMDeviceMotion!, error: NSError!) {
var orientation = UIDevice.currentDevice().orientation
if (error != nil) {
NSLog("\(error)")
}
var quat = motion.attitude.quaternion
//We Probably only need to check the Angle of the Roll (Phone Angle in Landscape mode)
var roll = GLKMathRadiansToDegrees(Float(atan2(2*(quat.y*quat.w - quat.x*quat.z), 1 - 2*quat.y*quat.y - 2*quat.z*quat.z))) ;
//Other Angles are available for more refinement to stabilty
//var pitch = GLKMathRadiansToDegrees(Float(atan2(2*(quat.x*quat.w + quat.y*quat.z), 1 - 2*quat.x*quat.x - 2*quat.z*quat.z)));
//var yaw = GLKMathRadiansToDegrees(Float(asin(2*quat.x*quat.y + 2*quat.w*quat.z)));
if(orientation == .LandscapeLeft) {
roll *= -1
}
if(roll > 100) {
roll = 100
} else if(roll < 0) {
roll = 0
}
self.currentRoll = roll
var pos = self.level.frame.height*CGFloat(roll/100)
var rect = self.levelIndicator.frame
rect.origin.y = pos
self.levelIndicator.frame = rect
if(roll > 85 && roll < 87) {
if(!countingDown) {
//This is the ideal roll position of the phone
self.levelIndicator.backgroundColor = UIColor.redColor()
}
} else {
countingDown = false;
self.levelIndicator.backgroundColor = UIColor.blackColor()
}
}
func stopReading() {
manager.stopDeviceMotionUpdates();
}
}
For anyone interested I ended up not using the UIDynamicAnimator for this but found a much simpler solution converting the returned Radians of the attitude change and using that to check the roll of the device. Also added a dispatch to the main queue to update the UI of the onscreen level.
func checkStability(motion: CMDeviceMotion!, error: NSError!) {
var orientation = UIDevice.currentDevice().orientation
if (error != nil) {
NSLog("\(error)")
}
var roll:Float = 0.0
if let attitude = motion.attitude {
roll = GLKMathRadiansToDegrees(Float(attitude.roll))
}
dispatch_async(dispatch_get_main_queue()) {
var pos = self.level.frame.height*CGFloat(roll/100)
var rect = self.levelIndicator.frame
rect.origin.y = self.level.frame.height-pos
self.levelIndicator.frame = rect
if(roll > 85 && roll < 90) {
//This is where I want the Roll to be
} else {
//The Roll is not correct yet
}
}
}

Creating Random Number

I am new to the programming world and am trying my hand at a simple math app. Basically i want to app to create two random numbers and then add them together. I then put the answer in a text field where the app checks to see if the answer is right or wrong. I have created this and it works however I cannot get the numbers to regenerate after the answer is correct. Any direction you can give on this I would be much appreciative.
Here is the code.
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.guess(self)
}
#IBOutlet weak var addend1: UILabel!
#IBOutlet weak var addend2: UILabel!
#IBOutlet weak var answer: UITextField!
#IBOutlet weak var response: UILabel!
//create numbers
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//remove keyboard
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
answer.resignFirstResponder()
return true
}
}
You can initialize the variables outside of the IBAction to get class level variable declaration. Then immediately calculate new random numbers once the correct answer is generated:
let newaddend1 = 0
let newaddend2 = 0
#IBAction func guess(sender: AnyObject) {
//Convert Random Numbers to String to be displayed in labels
var firstNumber = String(newaddend1)
var secondNumber = String(newaddend2)
//convert the answer in the text field to an integer
var integer = answer?.text.toInt()
//Convert Strings to Ints so they can be added
var newFirstNumber = firstNumber.toInt()
var newSecondNumber = secondNumber.toInt()
//Add Numbers
var correctAnswer = (newFirstNumber! + newSecondNumber!)
//Display the numbers
addend1.text = firstNumber
addend2.text = secondNumber
//Print correct number to log for test
println(correctAnswer)
println(integer)
//check your answer agains the correct answer
if (integer != nil) {
if (integer == correctAnswer) {
response.text = "Correct! The Answer is \(correctAnswer)!"
let newaddend1 = arc4random() % 11
let newaddend2 = arc4random() % 11
} else {
response.text = "Wrongo Bongo the correct answer is \(correctAnswer)!"
}
} else {
response.text = "Please put in a number for your guess"
}
}

Resources