Demo
Setup
First thing I tackled was setting up the L293D H-Bridge on the Bread Board.
I found myself referencing the following Diagram a couple times.
Step one is connecting your chip down the center of your board:
From here I connected the 3 power pins to my board’s power rail using a few Jumpers:
A few more Jumpers connect each side of the chip to ground:
Finally I use a couple Wires to connect both sides of my power and ground rails:
Using a little bit of double sided tape I stick my board onto the Car Chassis:
I also wired up each DC motor, and the battery pack to the board:
Next I wired up my Raspberry Pi‘s GPIO pins, connecting them to the L293D.
Once I’ve verified the GPIOs were connected properly, I used a couple rubber bands to strap the Pi, Portable USB Charger (I used a Vans Shoe Charger) and Web Cam to the cassis:
Code
On the Raspberry Pi I’m using Raspbian as the operating system, and installed a couple pieces of software:
* nginx
* Flask
* mjpg-streamer
* Rpi.GPIO
My nginx configuration is really basic and looks like this:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; location /stream { proxy_pass http://localhost:8080/?action=stream; proxy_set_header Content-Type "image/jpeg"; } location / { proxy_pass http://localhost:8000; } }
The Flask application is a bit janky, but gets the job done:
app.py
import RPi.GPIO as GPIO from flask import Flask, render_template from flask import request GPIO.setmode(GPIO.BCM) GPIO.setup(14, GPIO.OUT) GPIO.setup(15, GPIO.OUT) GPIO.setup(23, GPIO.OUT) GPIO.setup(24, GPIO.OUT) app = Flask(__name__) @app.route("/") def index(): return render_template('index.html') @app.route("/left") def left(): method = request.args.get('method') if method == 'stop': sig = GPIO.LOW else: sig = GPIO.HIGH GPIO.output(23, sig) return "OK" @app.route("/forward") def forward(): method = request.args.get('method') if method == 'stop': sig = GPIO.LOW else: sig = GPIO.HIGH GPIO.output(15, sig) GPIO.output(24, sig) return "OK" @app.route("/backward") def backward(): method = request.args.get('method') if method == 'stop': sig = GPIO.LOW else: sig = GPIO.HIGH GPIO.output(14, sig) GPIO.output(23, sig) return "OK" @app.route("/right") def right(): method = request.args.get('method') if method == 'stop': sig = GPIO.LOW else: sig = GPIO.HIGH GPIO.output(14, sig) return "OK" if __name__ == "__main__": app.run(host='0.0.0.0', port=8000, debug=True)
While the template contains a bit of Javascript to handle button presses:
templates/index.html
<html> <head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> img { margin-top: 25px; margin-bottom: 25px; } </style> <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> <script> // define our fired states to false var forward_fired = false; var backward_fired = false; var left_fired = false; var right_fired = false; // keydown event will start motor document.onkeydown = function() { if(event.keyCode == 87) { if(!forward_fired && !backward_fired) { forward_fired = true; button = document.getElementById('up'); button.className = 'btn btn-success btn-lg disabled'; console.log('start forward'); $.get("/forward") } } if(event.keyCode == 83) { if(!backward_fired && !forward_fired) { backward_fired = true; button = document.getElementById('down'); button.className = 'btn btn-success btn-lg disabled'; console.log('start backward'); $.get("/backward") } } if(event.keyCode == 65) { if(!left_fired && !right_fired && !backward_fired) { left_fired = true; button = document.getElementById('left'); button.className = 'btn btn-success btn-lg disabled'; console.log('start left'); $.get("/left") } } if(event.keyCode == 68) { if(!right_fired && !left_fired && !backward_fired) { right_fired = true; button = document.getElementById('right'); button.className = 'btn btn-success btn-lg disabled'; console.log('start right'); $.get("/right") } } }; // keyup event will stop motor document.onkeyup = function() { if(event.keyCode == 32) { console.log('beep'); $.get("/beep") } if(event.keyCode == 87) { if(forward_fired) { forward_fired = false; button = document.getElementById('up'); button.className = 'btn btn-default btn-lg disabled'; console.log('stop forward'); $.get("/forward?method=stop") } } if(event.keyCode == 83) { if(backward_fired) { backward_fired = false; button = document.getElementById('down'); button.className = 'btn btn-default btn-lg disabled'; console.log('stop backward'); $.get("/backward?method=stop") } } if(event.keyCode == 65) { if(left_fired) { left_fired = false; button = document.getElementById('left'); button.className = 'btn btn-default btn-lg disabled'; console.log('stop left'); $.get("/left?method=stop") } } if(event.keyCode == 68) { if(right_fired) { right_fired = false; button = document.getElementById('right'); button.className = 'btn btn-default btn-lg disabled'; console.log('stop right'); $.get("/right?method=stop") } } }; </script> </head> </body> <div class="container"> <div class="row"> <center> <img src="/stream" class="img-thumbnail"> </center> </div> </div> <!-- control buttons --> <div class="container"> <div class="row"> <center> <button id="left" type="button" class="btn btn-default btn-lg disabled"> <span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span> </button> <button id="up" type="button" class="btn btn-default btn-lg disabled"> <span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span> </button> <button id="down" type="button" class="btn btn-default btn-lg disabled"> <span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span> </button> <button id="right" type="button" class="btn btn-default btn-lg disabled"> <span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span> </button> </center> </div> </div> </body> </html>
I haven’t yet configured the Flask and mjpg-streamer processes to startup automatically, so I connect via a shell and start each in a screen session.
Once that is done connect to the running nginx server using your browser, you should be presented with a user interface similar to this:
Use your keyboard to control the car, just like a video game the key W moves forward, S backwards, A left, and D is right.
Component List
Here is a list of each of the components (or comparable) I used during the setup:
Raspberry Pi 3 Model B Motherboard
Official Raspberry Pi 3 Case – Red/White
uxcell White 8.5 x 5.5cm 400 Tie Points 400 Holes Solderless Breadboard
Microsoft LifeCam HD-3000 Webcam – Black (T3H-00011), 720p HD 16:9 Video Chat, Skype Certified
INSMA Motor Smart Robot Car Chassis Kit Speed Encoder Battery Box For Arduino DIY
Adafruit Dual H-Bridge Motor Driver for DC or Steppers – 600mA – L293D [ADA807]
Makerfocus 140pcs Breadboard Board Jumper Cable Wire Kit w Box
Happy Will 200 PCS Breadboard Jumper Wires/Jump Wire Mix Long and Short M/M for Circuit Board