Since Swift was introduced a little over two years ago, it has quickly grown to be among the top 20-active languages on GitHub (as of June 2016). Beyond writing apps for Apple's platforms, people have been using Swift to write backends for web services and even program Raspberry Pis. For a while now, I had a number of ideas for better domain-specific code editors and tools. After Swift was open sourced late last year, it became obvious Swift was the best choice for all of them.
- Wouldn't it be great if you could embed inline Swift code in Archimedes documents?
- Wouldn't it be great if you could program consumer robot kits like LEGO Mindstorms with Swift?
A week after Swift was open sourced, Alex and I began working on the infrastructure for a macOS Swift IDE that would enable us to ship all sorts of interesting domain-specific Swift-powered editors. Today, we're announcing the first fruits of almost 9 months of work.
Robotary is a robotics studio for macOS that lets entry-level programmers and experts alike program consumer robotics sets with Swift. It's designed to be so easy-to-use you can teach a week-long summer camp with it, and it's also designed to be powerful enough to facilitate more complicated projects. We're getting started with support for two generations of LEGO Mindstorms robotics sets, with support for more hardware along the way.
Today, there are two means of programming consumer robotics.
Block-based GUI tools (often based on LabVIEW) ship with LEGO Mindstorms but don't scale well when it comes time to write more sophisticated software. They also come with proprietary drivers, take up almost a gigabyte of disk space, and seem to have compatibility issues with each year's macOS release.
On the other side of the spectrum, domain-specific programming languages such as NXC have evolved over the years. Unfortunately, they're not very well-maintained (NXC was never updated for the EV3) and aren't based on standards (NXC stands for Not Exactly C).
We thought we could do better, so we wrote Robotary.
Instead of regurgitating features from Robotary's website, I wanted to explain its inner workings.
From the start, we knew Swift's speed, safety, and expressiveness make it a great choice for programming robots (Brad Larson agrees). Robotary ships with the standard version of Swift 2.2.1 and its Standard Library (and we'll have support for Swift 3 later this year). By supporting the standard version of Swift instead of a derivative, users get to use the exact same language constructs and APIs they are already familiar with. What's more, we built SourceKit directly into Robotary, so syntax highlighting and code completion are driven by the compiler, and our debugger is based on LLDB. All of these tools and frameworks are compiled directly into Robotary, so users don't have to have any external tools installed (including Xcode). To make installation painless, Robotary is available both inside and outside of the App Store as a single app bundle – more on this later.
On top of the Swift Standard Library, Robotary ships with RobotKit, a framework we designed for safely talking to robotic hardware from Swift. Thinking ahead, we designed it with many Swift 3 API guidelines in mind (e.g. lower enum case names) to make the move to Swift 3 as frictionless as possible. RobotKit includes support for interfacing with on-device buttons, LEDs, motors, sensors, and screens, and we'll continue to evolve RobotKit as we add support for new hardware.
RobotKit runs on top of a device communication layer we wrote ourselves. It's built on top of IOKit and runs entirely in userspace, isolated in separate processes. This approach is safer than a driver running in kernelspace as one mistake doesn't have the potential to crash the entire system. Moreover, because Robotary is completely independent of LEGO's proprietary drivers, it ships with zero external dependencies as I mentioned above. This makes it really easy to deploy in schools and labs.
A Sandboxing Story
As soon as we started the project, I knew shipping Robotary in the Mac App Store would be difficult. In fact, the biggest challenge of the project turned out to be working around the limitations of the Mac App Sandbox, which we spent months working on. There were three areas I had concerns about:
- The device communication layer underneath RobotKit
- The shared process in which device communication happens
- The LLDB-based debugger
Fortunately, we were able to overcome limitations in all of these areas.
com.apple.security.device.usb entitlement we were able to get all of our USB connectivity code up and running in the Sandbox. While Apple doesn't expose a Bluetooth entitlement in Xcode's Capabilities pane for Mac apps, one does in fact exist, and it was enough to get the usual
IOBluetooth calls working as well.
We also wanted to isolate the hardware-level code in separate processes, so we factored it out into XPC Services. This worked well, but we wanted a single shared XPC Service that the main app and our debug server – which runs in a separate process (more on this later) – could talk to. Fortunately, by simply changing the ServiceType of an XPC Service from "Application" to "User", we were able to get the behavior we were looking for (thanks XPC team!)
Speaking of XPC, we also patched SourceKit's XPC Service to run in the Sandbox with only about 50 lines of changes.
The biggest challenge in getting Robotary running in the Sandbox has been getting LLDB to work. Alex spent weeks writing a custom debug server that allows LLDB to run in the App Sandbox, and to my knowledge this is a first in the world. In fact, Robotary is the first and only Swift IDE available in the Mac App Store.
If you're interested in learning more about Robotary, be sure to check out its website or look for it in the Mac App Store. We're also on Twitter @robotaryapp, and you can always send an email if you have any questions.