Introduction: Smooth Web Browser Motor Control

About: Huge geek who loves trying new things. This generally gets me into some weird projects. Figured it was time to start sharing them!

Background

There are a million ways to control something remotely, but there are very few that are as accessible as an internet browser. Internet browsers are on almost every device, which makes them the prime interface for many projects. For another project I am working on, I need smooth/adjustable control of motors and servos, not just on/off, and I want easy control without a dedicated device, so this Instructable covers how I accomplished that.

Parts

  • Adafruit DC and Stepper Motor HAT
  • Raspberry Pi 3
  • Whatever you want to control (ie. Motor)
  • Pi and motor power supplies

*Some of this information will be a repeat of the Adafruit tutorial for this hat (which can be found HERE). If you already have your Pi and motor hat setup, skip to step 4, Software

Step 1: Wiring

The wiring for this project is fairly basic as most of the project is software. Either way, I'll cover the general idea:

Setup Motor Hat

Solder up the motor hat from Adafruit and attach it to the top of the Raspberry Pi. It should just plug onto the GPIO header. I recommend stand-offs between the two boards, but that isn't strictly necessary. Adafruit has this step covered fairly completely HERE

Power

The next step is to hook-up the motor power supply. This can be plugged into a wall supply, or a battery, whichever is easier. Keep in mind that the power supply you are going to use must match the motor you are using. If it won't supply enough power, the board can't fix that. There will be two headers for power in. All of your motors must run off the same voltage.

Motor

This board can handle 2 steppers, or 4 DC motors. In this case, I just want to use a single DC motor. Take the motor and attach the wires to the terminals labeled with an M#. For example, my motor will be the third one, so the wires need to go into the two terminals in front of the M3 label on the board.

Step 2: Configuration

I2C

To use the motor hat, I2C must be enabled on the Pi. You can do this with the GUI version, or the Terminal:

sudo raspi-config

In the options that come up, select Interfacing Options > I2C > Yes

Network

To access the Pi from a web browser, it needs to be on the network! You can use Wireless as there is minimal bandwidth used, or ethernet. How all of this is set up depends heavily on your network infrastructure.

Step 3: Software Install

There are a few different pieces of software framework to make this work:

Motor Hat

These are the libraries needed to "talk" to the motor hat.

Install dependencies

apt-get install python-smbus git python-dev

Download the motor hat library

git clone https://github.com/adafruit/Adafruit-Motor-HAT-Python-Library.git
cd Adafruit-Motor-HAT-Python-Library
sudo python setup.py install

Flask

Flask is the main "magic" here. It is a python web server that makes it simple for python to handle web requests

Install Pip (used to download and install python libraries)

sudo apt-get install python-pip

Have Pip install Flask

pip install Flask

Step 4: Finally, to the Interface!

This section is the real purpose of this Instructable. No matter what you want to control, this is the part that will control it all.

There are 2 parts that make this work, the interface and the web server. The interface is the set of nice sliders and feedback that you bring up on your phone or computer to control the remote motors. The server is the part that is living on the Pi, accepting the commands from the interface, moving the motors, and giving feedback.

Example

Download the example from the link below. I'll walk through how the code works

git clone https://github.com/david0429/web-motor-control.git

Interface (web_interface.html)

This is the main file that is presented to your browser when you connect to the Pi. It will have the sliders, buttons, drop-downs, etc. You could fancy it up with css, but that is mostly cosmetic and outside of this Instructable

The block of HTML code below contains 2 parts:

  • Input - Slider
    • It can also be a button or drop-down, etc.
    • It has a minimum, maximum, default value, and an ID/name that can be referred to elsewhere in the code
  • Span - Text
    • This will display the value that you are setting with the slider, or could display feedback from the server
    • This is completely optional and not necessary for control

This is mostly the visual part of the code

<div id="slidecontainer">
  <input type="range" min="-255" max="255" value="0" id="range1">
  <p>Value: <span id="range1_value"></span></p>
</div>

The next block of code is javascript. It is the "workhorse" of this webpage. It seems like a lot of code, but it really only does 1 basic task; send the value of the slider to python.

This first chunk of code just gets a handle on the 2 html elements we need and saves them in variables

var slider = document.getElementById("range1");
var output = document.getElementById("range1_value");

The next chink is the "connection" to python. This code sets an event to trigger whenever the sliders is moved because of the "slider.oninput" line. Every little slide of the slider (in this case, the input called "range1"), it will make a request to a remote server.

slider.oninput = function() {
  output.innerHTML = slider.value;
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
    }
  };
  xhttp.open("GET", "http://192.168.2.103:5000/set_speed?speed=" + slider.value, true);
  xhttp.send();
}

The open() function is the key here.

  • http://192.168.2.103:5000/ < This is the address of the Pi. It may be the hostname too depending on your network configuration. By default, the server will use port 5000
  • set_speed < This tells the server which function to call. More on this later
  • ?speed=" + slider.value This is a variable that you are passing to the Pi. In this case, it's the current position of the slider. If you want to pass multiple variables, separate them with a &. Doing this would let you program some more complex behaviours on the server-side

You can have as many controls/sliders as you want, just duplicate those two blocks of code above, change the variable and id names, and change which "function" you're calling and you're done!

Python - Flask (motor_control.py)

This Flask server is the actual controller that accepts the requests from the web interface. This is the brain of you robot/machine/device,

This first chunk of code is a basic python function. The name is fairly unimportant, as long as it is unique. Having the @app.route("/") just before it tells Flask that this function should be called whenever someone requests the root page of the web server.

When this function is run, it will open the web_interface.html file (discussed previously) and return everything in it back to the user. This way, you can store your web interface in another file so it is much cleaner. Having the flask server return the interface also helps avoid cross-site security warnings

@app.route("/")
def web_interface():
  html = open("web_interface.html")
  response = html.read().replace('\n', '')
  html.close()
  myMotor.setSpeed(0)
  return response

This next chunk is the portion that works with the slider and the motor. Whenever someone requests the "set_speed" page/resource, Flask calls this function. Like above, the @app.route("/set_speed") line tells Flask to do this.This is the "open" line in the section above. Every tick of the slider, this page/function/resource is called.

Once in the function, the "speed" variable is pulled out of the request. If there were multiple variables passed in this request, just use this line once for each variable.

After that, it's basic motor commands, setting speed and direction and sending them to the motor hat.

@app.route("/set_speed")
def set_speed():
  speed = request.args.get("speed")
  print "Received " + str(speed)  direction = Adafruit_MotorHAT.FORWARD
  if int(speed) < 0:
    direction = Adafruit_MotorHAT.BACKWARD  myMotor.run(direction)
  myMotor.setSpeed(abs(int(speed)))

This last line starts the Flask server. If it didn't have anything between the brackets, you could only access the webpage from on the Pi, but with the '0.0.0.0', you can access the page from anywhere within the network.

app.run(host= '0.0.0.0')

Like the interface, you can have as many functions as your want to make your application more complicated/flexible. Just make a new function with a unique name and a unique route above it and you're good

Step 5: Usage

Once both of these have been set up, run the web server by typing the following command:

python motor_control.py

Now that this is running, from any browser in your network, visit the Flask webpage:

http://raspberry-pi-ip:5000

Note: replace "raspberry-pi-ip" above with either the IP or the hostname of your Pi.

If all goes well, you should see your basic web page! You should also see a message in the terminal where the web server is running indicating that it served a page.

Now, try moving the slider. Again, if all is working, you should see your motor start moving! The slider will control speed and direction.

Troubleshooting

  • If the page doesn't appear and you get an error 500, it means there is a mistake in your python. Head back to the terminal to see the error listed.
  • If a page loads but it looks weird, there is an issue in your html page.
  • If you move the slider and you don't see messages coming up in the server terminal, make sure the IP and page are correct in your "open" function in the web interface and open your Javascript console in your browser and fix any errors
  • If you move the slider and you see messages coming up in the server terminal, but you don't see your motor moving, make sure your motor hat has power, the motor is properly connected to the right port, and your python code is driving the right motor

Step 6: Final Thoughts

*Note - This instructable doesn't take security into account at all. Use this on a public network or allow direct access from the internet at your own risk.

With some very minor tweaks you could control servos, steppers, LEDs, even full interfaces. With some fancy html and CSS, you could make a cross-platform controller that is really sleek and even adds to current projects!

Make It Move Contest 2017

Participated in the
Make It Move Contest 2017