Swiftpack.co - Package - peterhagelund/iRobot

iRobot

Library for controlling iRobot Roomba robots.

Copyright and License

Copyright (c) 2019 Peter Hagelund

This software is licensed under the MIT License

See LICENSE.txt

Please note: Pay particular attention to the bottom half of the MIT license that talks about the software being provided "AS IS" and that there is no warranty of any kind. If you choose to utilize this software to control (or at least attempt to control) a physical device in the real world, you run the risk of damaging the vaccum cleaner and/or your dwelling and/or any furniture or other belongings you may keep there and/or any carbon-based lifeforms that might inhabit your space. This is especially true if you choose to place the Roomba OI in full mode - in which case all of the failsafes the talented iRobot engineers have put in place are completely disabled. In full mode you run the risk of not catching an overcurrent condition in the motors, having the vacuum cleaner fall down a staircase, and possibly hit and ingest your pet(s) or a child. Read the OI specification very carefully and test your software to destruction before letting this thing loose in your house. Ye be warned!

Please note: I am in no way affiliated with iRobot or any of its subsidiaries or suppliers. I have used their products for several years (my first one was a Roomba Red) and have written libraries similar to this one in Java, C, C++, Python, Go, and likely other languages simply because I enjoy doing so.

Installation and Setup

  • Clone the repository (git clone https://github.com/peterhagelund/iRobot.git)
  • cd iRobot/
  • swift build
  • swift package generate-xcodeproj
  • open iRobot.xcodeproj/

Documentation

The source contains documentation comments suitable for jazzy

TL;DR:

  • [sudo] gem install jazzy
  • jazzy --clean --author "Peter Hagelund" --module iRobot --min-acl private
  • open docs/index.html

Testing

Since a connection to the vacuum cleaner is abstracted through the Connection protocol, it's easy to test things through a mocked up implementation (MockConnection).

Run swift test or hit ⌘U from within Xcode.

Please note: I currently only have access to an elderly Roomba 555 so testing of this library has not been exhaustive to other/newer models yet. Since the 555 is serial only, I have only implemented a serial version of the Connection protocol (SerialConnection). At the time of writing (August, 2019) I have just taken delivery of a 690 with WiFi but not yet dug deep into that.

Using

For projects that depend upon iRobot, make sure Package.swift contains the correct dependency:

// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "<package name>",
    products: [
        .library(
            name: "<package name>",
            targets: ["<your target>"]),
    ],
    dependencies: [
        .package(url: "https://github.com/peterhagelund/iRobot.git", from: "1.0.1")
        .package(url: "https://github.com/...", from: "...")
        .package(url: "https://github.com/...", from: "...")
    ],
    targets: [
        .target(
            name: "<your target>",
            dependencies: ["iRobot", "...", "..."]),
        .testTarget(
            name: "<your test target>",
            dependencies: ["<your target>"]),
    ]
)

The general approach is:

  • Instantiate an implementation of Connection, such as SerialConnection which takes a SerialPort.
  • Instantiate a new Roomba instance.
  • Start the OI by invoking Roomba.start(), at which time - if successful - the OI is now in passive mode.
  • Put the OI in either safe or full mode. Please re-read the warnings above about - in particular - full mode.
  • Drive the Roomba through Roomba.driveDirect(...) and Roomba.drivePWM(...).
  • Use its motors through Roomba.motorsPWM(...).
  • Have it return sensor packets through Roomba.sensors(...) or Roomba.queryList(...). You can also have the Roomba continuously (every 15 ms) stream packets by invoking Roomba.stream(...) - I tend to not use that much and havne't spent a lot of time testing it.
  • When done, put the OI back in passive mode by invoking Roomba.start().

Please note: This library is insufficient for any real-world application. You'll need additional layers on top of it to continously monitor the sensors and make updates to the wheels and/or motors. You can liken this library to the bottom layer in an auto pilot: it knows how to actuate the plane's control surfaces and read pitot tubes and other sensors, but something needs to tell it where and how to go so it doesn't just careen into, say, a mountain side or the ground killing everyone onboard. You didn't forget to read the warnings above, did you?

import Serial
import iRobot

// Assume standard settings for the OI
guard let serialPort = SerialPort(device: "/dev/tty.usbserial-A800K6ZJ", baudRate: .bps115200, parity: .none, dataBits: .bits8, stopBits: .bits1) else {
    NSLog("Unable to create serial port")
    return
}
let connection = SerialConnection(serialPort: serialPort)
let roomba = Roomba(connection: connection)
roomba.logging = true
do {
    // Bring OI on-line in passive mode
    try roomba.start()
    // Enter full mode
    try roomba.full() // Pets and children beware!
    let packet3 = try roomba.sensors(type: Packet3.self)
    NSLog("Packet = \(packet3)")
    // Go forward at 100 mm/s for 2 seconds
    try roomba.driveDirect(velocityLeft: +100, velocityRight: +100)
    Thread.sleep(forTimeInterval: 2.0)
    // Stop and let the motors/wheel settle
    try roomba.driveDirect(velocityLeft: 0, velocityRight: 0)
    Thread.sleep(forTimeInterval: 0.5)
    // Go backward at 100 mm/s for 2 seconds
    try roomba.driveDirect(velocityLeft: -100, velocityRight: -100)
    Thread.sleep(forTimeInterval: 2.0)
    // Stop and let the motors/wheel settle
    try roomba.driveDirect(velocityLeft: 0, velocityRight: 0)
    Thread.sleep(forTimeInterval: 0.5)
    // Back to passive mode
    try roomba.start()
} catch let e as POSIXError {
    NSLog("Error: \(e.code.rawValue)")
} catch {
    NSLog("Unexpected error: \(error)")
}

Please note: If your code fails at any time after instructing the Roomba to drive, it will continue to drive until some piece of code stops it, so (much more) error handling (see below) is needed than what is described above.

Error Handling

Under the covers (except when using the MockConnection) the Roomba communicates with a real-world, physical vacuum cleaner, so anything can go wrong at any time.

All public functions declare throws and in case of an error within the Connection implementation rethrows that error (usually a POSIXError instance).

Github

link
Stars: 0
Help us keep the lights on

Dependencies

Used By

Total: 1