A Simple Telepresence Robot

I’m teaching a high school astronomy class this year (which I thoroughly enjoy, by the way!), and one of my students lives a couple hours away and uses Skype to attend the class sessions.  The class features a lot of group discussion and it’s kind of difficult for this student to follow what’s going on when all he can see on the screen is me.  I thought, “wouldn’t it be great if the student could rotate the camera around to see who’s talking?”

After contemplating that for a few minutes I realized that I could actually build something to enable that pretty quickly.  Most of my projects end up taking weeks of calendar time to complete (a couple hours here, a couple hours there, wait for an order to get shipped, etc.) but this one actually came together over the course of one weekend with parts I had on hand, just like I’ve always dreamed a project should go.

Here’s what the finished project looks like:

IMG_20171119_193623

Design

I usually run the Skype session with the student on my smartphone.  I wanted a device that would have these features:

  • Hold my phone upright in a secure fashion
  • Be able to rotate the phone 360 degrees
  • Allow the student to remotely control the rotation of the device
  • Be reasonably responsive to rotation commands
  • Operate silently so it doesn’t distract the class
  • Be powered from a standard USB port or charger.

I have a 3D printer so building the physical body wasn’t a problem.  I designed a sort of sleeve into which I could insert my phone, which would be attached to the shaft of a motor in the base of the device.

I had an Adafruit stepper motor on hand which was perfect for the job of rotating the phone.  It’s small, practically silent, can rotate 360 degrees, and runs on 5V.  I also had an L293D dual H-bridge motor driver IC suitable for driving this motor.

I’ve used the Particle Photon for a few previous projects and I really like it.  Fortunately I had an extra one on hand which made the remote control part really easy.  Particle has a really fantastic cloud platform that makes it trivial to invoke a function on the device via an HTTP call from anywhere on the internet.  That’s all I needed to build a link between a control web site and the robot.  There’s definitely some risk that Particle may go out of business some day and the cloud services will disappear, but for right now it’s hard to beat the speed with which you can build internet-enabled devices.  I think it’s an acceptable tradeoff for hobby projects like this.

Body

I designed the body of the telepresence robot in Fusion 360.  As an aside, I highly recommend Fusion 360 for designing physical objects where you might need to iterate on the proper physical size, because you can easily go back and change just the dimensions you need to tweak without rebuilding the whole object.  You can get a free hobbyist license as long as you’re not using it for profit.

The CAD files and STL files are available on Thingiverse.  I sized the sleeve for my Google Pixel phone, but if you download the Fusion 360 source file you can easily tweak the dimensions to fit whatever device you’re using.

The stepper motor is mounted inside the base using two 25mm M3 buttonhead screws.  It’s important to use screws with very shallow heads so that you get enough clearance for the phone sleeve to rotate above them.  The same two screws also hold the perfboard with the electronics.

The phone sleeve is attached directly to the motor shaft using a small set screw on the back.

IMG_20171119_193418

IMG_20171119_194528

Electronics

I used stripboard to solder the electronics together, but regular perfboard would work just as well.  I based the circuit on this Adafruit tutorial diagram, but using a Photon instead of an Arduino.  Power to the L293D comes from the VIN pin on the Photon which is powered directly from the USB port.  The layout needs to be kind of compact to fit in the base but it wasn’t hard to work out a good strategy after a little thought.

IMG_20171119_194751

Code

The code for the Photon can be found in the GitHub repository, but it’s pretty simple.  Here it is:

#include <Stepper.h>

int in1Pin = D0;
int in2Pin = D1;
int in3Pin = D2;
int in4Pin = D3;

Stepper motor(513, in1Pin, in2Pin, in3Pin, in4Pin);  

void setup() {
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(in3Pin, OUTPUT);
  pinMode(in4Pin, OUTPUT);

  motor.setSpeed(8);

   Particle.function("move", moveMotor);
   // This is saying that when we ask the cloud for the function "move", it will employ the function moveMotor() from this app.
}

void loop() {

}

int moveMotor(String command) {
    if (command=="left") {
        motor.step(50);
        return 1;
    }
    else if (command=="right") {
        motor.step(-50);
        return 0;
    }
    else {
        return -1;
    }
}

We’re using the Stepper library that’s available through the Particle cloud-based IDE, which has the same API as the stock Arduino stepper library.  We simply configure four output pins and then implement a function “moveMotor” that can be called remotely through the Particle cloud platform.  When the function is called it receives one string parameter that is the command we should execute, either “left” or “right”, then we just command the motor appropriately.

Web Site

My day job uses the Microsoft stack so the fastest route for me to get to a functional web site was to whip up something using ASP.NET Core.  If you’re more comfortable with Node or whatever, that’s fine too.  The full source code for the remote control web site can be found in the GitHub repository, but here are the important bits minus all the boilerplate code.

The javascript code that runs in the browser just invokes two server APIs:

<script>
    $(function() {
        $('#moveLeft').click(function() {
            $.post("api/moveleft");
        });
        $('#moveRight').click(function() {
            $.post("api/moveright");
        });
    });
</script>

And the code on the server side invokes the function on the Photon:

public class HomeController : Controller
{
    private HttpClient client = new HttpClient();
    private readonly IConfiguration configuration;

    public HomeController(IConfiguration configuration)
    {
        client.BaseAddress = new Uri($"https://api.particle.io/v1/devices/{configuration["device"]}/");
        this.configuration = configuration;
    }

    public IActionResult Index()
    {
        return View();
    }

    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }

    [Route("api/moveleft")]
    public async Task MoveLeft()
    {
        await DoMove("left");
    }

    [Route("api/moveright")]
    public async Task MoveRight()
    {
        await DoMove("right");
    }

    private async Task DoMove(string direction)
    {
        var content = $"access_token={configuration["access_token"]}&args={direction}";
        await client.PostAsync("move", new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded"));
    }
}

The call to the Particle cloud platform is done on the server, not the browser, so we can keep the device ID and access token secret.

Screen Shot 2017-11-19 at 9.33.55 PM

I hosted the web site in Azure but it’s using no special services so it can be hosted pretty much anywhere that can host ASP.NET Core apps.  Total response time, from clicking one of the buttons on the web site to having the device rotate the phone, is typically under one second, which is good enough for my purposes.

That’s all you need to an internet-enabled device up and running.  It doesn’t get much simpler than that!