ARKit and CoreLocation: Part Three
Navigation With Linear Algebra (and Trig)
Demo CodeARKit and CoreLocation: Part OneARKit and CoreLocation: Part TwoARKit and CoreLocation: Part Three
This post is the third part of the series on ARKit and Core Location. In the first part we went over the basics of ARKit and placing objects, in the second part, we figured out how to calculate the coordinates we need to take our trip and how to translate those locations from two-dimensional plots into the three-dimensional real world.
Now it’s time to apply what we’ve learned. I’ve created a demo project which incorporates all the thing we’ve previously gone over into practical application. If you try to run it, be sure to change the destination location. Otherwise, it might crash if you’re too far away (we’ll fix that later on.) This is just the rough functionality.
You can checkout the finished code here: https://github.com/chriswebb09/ARKitNavigationDemo
The demo project I put up is intended to demonstrate the concept rather than provide a great user experience. But what are some things we could do to make it better?
Region — For one, we could render far fewer nodes. In fact, it’s a bit distracting that the entire trip is rendered. To fix this, we could render one leg of the journey at a time. Then we could use our location service to monitor for when we enter that region, or we could calculate the distance from the point of view to the last node in the leg triggering a mechanism to render a new leg and remove the old when they are in proximity. Dynamic Destination — Another easy way we could improve it is we could allow the user to set their destination inside the application, instead of hard-coding our destination.Reset — As the project is as of this writing, the reset functionality hasn’t been completed. Sometimes ARKit gets confused, sometimes the GPS gets confused (more on the location problems in a bit.) So we can build a mechanism which resets the screen so we can start over. That way you don’t have to quit to reset the trip.Steady Our Node Positions — Finally, we could steady the positions of our nodes by setting them to a static position once they’ve been placed.
There were a bunch of challenges that I came across while working with ARKit and Core Location. Some of these problems were solvable, others were more fundamental and could be not solved with the current hardware. Even if they aren’t solvable, you can mitigate the worst consequences of them with a few quick changes.
To begin with, the biggest challenge you face when working with ARKit and Core Location is the issue of location accuracy. If you’ve ever been to NYC, you’ll notice that the grid system creates these canyons of concrete, steel, and glass. While it is pretty awesome to look at, if you’re trying to locate someone this terrain can pose a problem. GPS signals are microwaves beamed down from a satellite which means that the signal can be absorbed or reflected by surfaces. This interference is particularly noticeable in NYC. The effect can be that your location (as your phone perceives it) jumps around erratically.
In PokemonGO, one of the major features is that Pokemon get geo-positioned on the map. You had to be within a certain radius of the location of the Pokemon in order engage it. This led to an interesting effect. You could be sitting somewhere playing and then get warped to an area several blocks away and be able to engage with the Pokemon at the new location only then to get warped back to your original location.
With a game like PokemonGO, that’s not a huge deal, and it could even be a bit of a bonus. With navigation, this is another story. One solution is to stop updating the locations once the markers have been set or only use it at certain intervals. While this isn’t the best outcome, it is the easiest to implement. This erratic functionality in addition to draining your battery, AR/SceneKits coordinate system provides ample reason to explore a different set of tools to maintain awareness of your location.
Given that location monitoring and awareness is fundamental to our project, before we go further, we need to go over how to monitor a users location as they use the app.
CLLocationManager: CLLocationManager is the object that manages the location-related events to your app.
We’ll also need to cover Apple Privacy. Apple’s requires that your application ask the users permission and have them agree before you can monitor their location. The are multiple levels of privacy in regards to monitoring the users location. You should add the appropriate one to your info.plist.
When-in-use authorization: Your app can use most services but cannot use services that automatically relaunch the app. Your app must always start services while running in the foreground. If you enable the background location capability for your app, a suspended app will be woken in the background to handle location events. However, if your app is not running, it will not be launched.Always authorization: Your app can use all location services, and it can start those services from either the foreground or the background. If a location-related event occurs when your app is not running, the system launches your app and delivers the event.
Our LocationService should conform to the CLLocationManagerDelegate protocol. We don’t want to tie our LocationService directly to the controller so we’ll make a delegate to loosely couple location update to our UI.
Now when a location update happens in our LocationService, we can push that new information into our controller to work with.
Now that we’ve gotten our delegate squared away let’s move onto the LocationService! Because CLLocationManagerDelegate inherits from NSObjectProtocol, this class should be a subclass of NSObject and conform to the CLLocationMangerProtocol protocol. It may sound weird to throwback to NS classes, but since everything in Objective-C inherits from NSObject, and Apple’s mission is to make Swift and Objective-C as compatible as possible you will see NSObject pop up from time to time.
NSObjectProtocol: The base protocol to which all Objective-C objects conform to.NSObject: The base class of most Objective-C classes. Inheriting from NSObject gives the subclass an interface to the system runtime and the basic behavior of Objective-C objects.The Cocoa root class NSObject adopts this protocol, so all objects inheriting from NSObject have the features described by this protocol.
Whatever class we instantiate the LocationService in, we can now use our protocol conformance to pass location updates between that class and the service.
That should cover location monitoring for now. In the next post, we’ll setup MapKit to help us navigate.