2018-09-01 - By Dhiraj Sai Vemuri, Amritha Agnes Sebastian, Ashitha Placid, Robert Elder
Yes you can, and the actual total cost of all parts including shipping, import duties, and taxes was around $132.45 CAD or $101.51 USD.
This article is a review of a capstone project completed by Dhiraj Sai Vemuri, Amritha Agnes Sebastian, and Ashitha Placid. The goal for their project was to determine if was possible to assemble a robot tank chassis, a Raspberry Pi Computer, and several other components to produce a final solution that can do all of the following:
- Support remote streaming video wirelessly.
- Make use of the tilt/pan camera control wirelessly.
- Remotely control and administrate the tank over an SSH connection.
Furthermore, the objective was to do all of this inexpensively, and quickly to demonstrate that it is possible. The group was successful in achieving all of these goals.
- A cheap eBay robot tank chassis with the listing title of 'SN900 Smart Robot Germany Tank Car Chassis Kit Rubber Track Crawler for Arduino' for $23.27 CAD including shipping.
- A cheap eBay tilt/pan camera mount with the listing title of 'PT Pan/Tilt Camera Platform Anti-Vibration Camera Mount w/ 2 Servos Aircraft FPV' for $5.41 CAD including shipping.
- A cheap eBay Raspberry Pi Camera with the listing title of 'Camera Module Board 5MP Webcam Video 1080p 720p for Raspberry Pi 3 & Pi 2' for $7.98 CAD including shipping from eBay seller 'deerap'.
- A cheap eBay motor driver chip '10PCS L293D L293 Push-Pull Four-Channel Motor Driver IC DIP-16 NEW' (only 1 was needed) for $3.52 CAD including shipping from eBay seller 'alice1101983'.
- A cheap eBay protoboard for $2.50.
- A Raspberry Pi 3 Model B purchased from DigiKey for $55.07 CAD including shipping.
- Two of '10 Pcs Snap 9V (9 Volt) Battery Clip Connector I Type Black w Cable LW' from eBay which cost approximately $1.40 CAD including shipping and left a surplus of 8 connectors.
- One of 'For 3 X AA Battery Hard Holder Case Box Plastic Storage With Wire Leads Black' from eBay which cost approximately $1.63 CAD including shipping.
- A bread-board prototyping kit from Addicore cost $11.50 USD + Shipping + import duties. I have recently found these much cheaper (although of inferior quality on eBay for $5.67 CAD shipping included with the listing title 'New MB-102 Solderless Breadboard Protoboard 830 Tie Points 2 buses Test Circuit');
- The students also purchased a cheap Lithium Ion battery bank for which the cost was not recorded, but stated as 'About $5 or $6'.
- Three disposable AAA batteries and two 9V batteries: Estimate $10.
- A cheap 8GB Micro SD Card purchased locally for about $10.
This puts the total cost estimate of all parts at around $23.27 + $5.41 + $7.98 + $3.52 + $2.50 + $55.07 + $1.40 + $1.63 + $5.67 + $6.00 + $10.00 + $10.00 = $132.45 CAD including shipping charges and all ancillary fees of shipping, import duties and taxes. This also assumes the use of the cheaper breadboard prototyping kit. As it stands today, $132.45 CAD = $101.51 USD which makes this even more impressive. Depending on your preference for battery life, you could probably even improve on the costs of power supply.
A screenshot of a streaming video session with the tank:
How To Stream Video From Raspberry Pi To Linux Desktop
Below, I'll discuss the steps for how to set up streaming video from the Raspberry Pi to a local laptop running Linux. Before I go into detail, let me set you up to properly understand that instructions I'm about to give. Your default assumption of how the streaming video set up goes is probably something like this:
- Step 1) Start the stream on the Raspberry Pi.
- Step 2) Connect to the stream from the Raspberry Pi on your local Laptop.
But what I'm actually going to describe is the following:
- Step 1) Start a streaming video server on your local Linux laptop that can support any number of streams and clients (in our case, we'll just have one stream (from the pi) and one client (you watching the video)).
- Step 2) Start the stream on the raspberry pi and tell it to point to the server on your laptop that was set up in step 1.
- Step 3) On you local laptop, start a client that connects to the streaming server you set up in step 1 to watch the stream from the server hosted on that same computer.
This is by no means the best way, it is simply a way that works. Furthermore, you should note that the setup described here only shows you how to stream the video over you local LAN (the computers in your house connected to the router), but you can stream it from anywhere on internet if you set up port forwarded tunnel through SSH using a proxy server, although that is beyond the scope of this article.
Step 0) PI Installation and Setup For Video
This part may be different depending on what build of the raspberry pi OS you use, but in this case, I have tested these instructions for the '2018-06-27-raspbian-stretch.img' image that has sha256sum 65308c4a52cb2a6e7995c67e66aceca68a1b1944f2aacb1f89be55f4db9d48ab. Also make sure that your raspberry pi camera is connected to the PI first.
First, open a terminal or use an SSH connection to get command-line access to the pi. Then run the following commands on the Raspberry Pi. Note that the update command may download a lot of data and take a while, so make sure you're on a good network connection first:
sudo apt-get update sudo apt-get upgrade sudo apt-get install ffmpeg sudo raspi-config
The last command will open up a menu where you can select the interfacing options to enable the camera. To get there select 'Interface Options':
Then select the camera:
Choose 'Yes' to enable it:
Now, select 'Finish', and select reboot. Now, try:
raspistill -o foo.jpg
If you try the above command before you've enabled the camera, you'll get the following message:
mmal: mmal_vc_component_create: failed to create component 'vc.ril.camera' (1:ENOMEM) mmal: mmal_component_create_core: could not create component 'vc.ril.camera' (1) mmal: Failed to create camera component mmal: main: Failed to create camera component mmal: Camera is not enabled in this build. Try running "sudo raspi-config" and ensure that "camera" has been enabled
If you still get this message, it may be because you forgot to reboot the PI. If you do get an image in foo.jpg, then you've proven that the camera works, so can we can proceed with further setup steps.
By default, the Raspbian OS does not load the Linux kernel module required for loading /dev/video0 which gives an easy way for applications such as ffmpeg to read video from the camera. You can temporarily load this module with the following command:
sudo modprobe bcm2835-v4l2
The above command will, however, only keep this kernel module loaded until the next time you reboot: After you boot up, /dev/video0 will be gone again, and you'll need to re-run that command. To prevent the need to doing this on every boot, you can do:
sudo sh -c 'grep "bcm2835-v4l2" /etc/modules || echo "bcm2835-v4l2" >> /etc/modules'
The above command will search the file '/etc/modules' for the 'bcm2835-v4l2' module name, and if it's not present, it will be added to the end of the file. The 'sudo sh -c' part makes sure it runs as the root user so we can modify the /etc/modules file. Now you should be able to verify that the file /dev/video0 is now available. Run the following command to check:
If this works, you'll see it echo back the same file name. If it doesn't, then you'll see:
ls: cannot access '/dev/video0': No such file or directory
Now try to verify that ffmpeg can read from /dev/video0 by making a short local video from the camera (you can stop the recording whenever by using CTRL+C):
ffmpeg -f v4l2 -s 320x240 -r 25 -i /dev/video0 test.avi
Watch the video and verify that this step worked. Now you've completed all the necessary installation procedures.
Identify IP Addresses
Before we move on, let's figure out what the LAN IP address is of your raspberry pi and your laptop where you want to watch the stream. Run this command on your personal laptop to see info about your IP address:
I see something like this:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: wlp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 12:34:56:78:90:ab brd ff:ff:ff:ff:ff:ff inet 192.168.0.122/24 brd 192.168.0.255 scope global dynamic wlp2s0 valid_lft 574471sec preferred_lft 574471sec inet6 abcd:efab:cdef:abcd:efab:cdef:abcd:efab/64 scope global temporary dynamic valid_lft 3599sec preferred_lft 3599sec inet6 abcd:efab:cdef:abcd:efab:cdef:abcd:efab/64 scope global mngtmpaddr noprefixroute dynamic valid_lft 3599sec preferred_lft 3599sec inet6 fe80::6a4e:9080:87ea:41c1/64 scope link valid_lft forever preferred_lft forever
Which tells me that my local IP address of my laptop is 192.168.0.122.
Running the same command on the PI, I see:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether b8:27:eb:d7:0e:84 brd ff:ff:ff:ff:ff:ff inet 192.168.0.116/24 brd 192.168.0.255 scope global eth0 valid_lft forever preferred_lft forever inet6 2607:f2c0:e572:1701:7de9:d326:3c88:837e/64 scope global mngtmpaddr noprefixroute dynamic valid_lft 3597sec preferred_lft 3597sec inet6 fe80::f127:7496:1ea1:19b2/64 scope link valid_lft forever preferred_lft forever 3: wlan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000 link/ether b8:27:eb:82:5b:d1 brd ff:ff:ff:ff:ff:ff
So the local IP address of the Raspberry PI is 192.168.0.116. Now that we have this information, let's setup the streaming video!
Step 1) Launch An FFServer
This step will take place on your local laptop, and it involves setting up a streaming server that could, if you wanted to, provide streaming services for multiple stream sources and many stream clients. We're just going to use it with one stream source, and one client. You can install ffserver with the following command:
sudo apt-get install ffmpeg
Once the server is installed, create a simple config file for the ffserver config. Let's create one at '~/pi-ffserver.conf' and put the following contents into it:
HTTPPort 8090 # Accept connections from anywhere: HTTPBindAddress 0.0.0.0 # Max number of simultaneous clients MaxClients 1000 # Max bandwidth per-client (kb/s) MaxBandwidth 10000 # Suppress that if you want to launch ffserver as a daemon. NoDaemon <Feed pi-video-feed.ffm> File /tmp/pi-video-feed.ffm FileMaxSize 5M </Feed> <Stream pi-stream.swf> Feed pi-video-feed.ffm Format swf VideoCodec flv VideoFrameRate 15 VideoBufferSize 80000 VideoBitRate 100 VideoQMin 1 VideoQMax 5 VideoSize 640x480 PreRoll 0 Noaudio </Stream>
Now, let's launch the server:
ffserver -f ~/pi-ffserver.conf
Keep the above terminal open as long as you want the streaming server to be up, then press Ctrl+C to shut it down when you're done.
Step 2) Start Sending Video
Log into the raspberry pi and run the following command in a terminal or through ssh:
ffmpeg -f v4l2 -s 320x240 -r 25 -i /dev/video0 http://192.168.0.122:8090/pi-video-feed.ffm
but make sure to replace 192.168.0.122 with the address of your laptop, not mine! This command will run until you decide to stop sending the video, and you can stop sending the streaming video by pressing Ctrl+C.
Step 3) Start Watching Video
Now, to actually watch the video stream. Perform this next step on whatever computer you watch the video from on your local LAN:
but make sure to replace 192.168.0.122 with the address of your laptop, not mine! This should be the same IP where you ran the 'ffserver' command.
It may take a minute or so before the video stream shows up because it will probably wait for the next key frame. If it works you'll eventually see a video window pop up. You may see some red text that says 'warning: first frame is no keyframe', but you just have to wait a minute or so for the first keyframe. When the video first starts, it may run quickly for a while until it catches up. You'll also see a few seconds of delay in the feed, but this guide it just a starting point! Playing around with the video encoding formats, buffer sizes, and network latency can affect the amount of lag you experience.
Tank Motion Control
The students did not have time to create a detailed circuit diagram, but here are a few pictures of the circuit that they came up with. Here are the connections to GPIO pins on the Raspberry Pi:
Here is a picture of where the GPIO pin connections lead to on the H-bridge chip:
And a higher-level view of the entire configuration:
And here is a picture of the soldered points on the under side of the protoboard:
Wireless Remote Control
The tank was controlled wirelessly by first using SSH to access the tank over a WiFi connection. Once the SSH session was active, running a small Python script 'tank.py' enabled the user to control various functions of the tank:
import RPi.GPIO as gpio import time #import picamera import sys import termios import tty gpio.setmode(gpio.BOARD) gpio.setup(8,gpio.OUT) gpio.setup(10,gpio.OUT) #p=gpio.PWM(10,50) #p.start(7.5) #q=gpio.PWM(8,50) #q.start(7.5) def getch(): fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(fd) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch def gpioInit(): gpio.setmode(gpio.BOARD) #camera = picamera.PiCamera() gpio.setup(7,gpio.OUT) gpio.setup(19,gpio.OUT) gpio.setup(13,gpio.OUT) gpio.setup(15,gpio.OUT) def pwmUpperStart(dutyCycle): pwmInit() duty=dutyCycle q.ChangeDutyCycle(duty) def pwmLowerStart(dutyCycle): pwmInit() duty=dutyCycle p.ChangeDutyCycle(duty) def pwmInit(): gpio.setmode(gpio.BOARD) gpio.setup(8,gpio.OUT) gpio.setup(10,gpio.OUT) def reset(): time.sleep(.01) def stop(): gpioInit() gpio.output(7,0) gpio.output(19,0) gpio.output(13,0) gpio.output(15,0) print("stop") def forward(): gpioInit() gpio.output(7,1) gpio.output(19,0) gpio.output(13,1) gpio.output(15,0) print("forward") time.sleep(0.1) stop() def backward(): gpioInit() gpio.output(7,0) gpio.output(19,1) gpio.output(13,0) gpio.output(15,1) print("backward") time.sleep(0.1) stop() def right(): gpioInit() gpio.output(7,0) gpio.output(19,1) gpio.output(13,0) gpio.output(15,0) print("right") time.sleep(0.1) stop() def left(): gpioInit() gpio.output(7,0) gpio.output(19,0) gpio.output(13,0) gpio.output(15,1) print("left") time.sleep(0.1) stop() def lowerServoMiddle(): pwmLowerStart(7.5) print("lowerServoMiddle") def lowerServoLeft(): pwmLowerStart(12.5) print("lowerServoLeft") def lowerServoRight(): pwmLowerStart(2.5) print("lowerServoRight") def upperServoMiddle(): pwmUpperStart(7.5) print("upperServoMiddle") def upperServoLeft(): pwmUpperStart(12.5) print("upperServoLeft") def upperServoRight(): pwmUpperStart(2.5) print("upperServoRight") bol=True; try: stop() while bol: direct=getch() if direct=='w': forward() elif direct=='s': backward() elif direct=='a': left() elif direct=='d': right() elif direct=='i': upperServoLeft() elif direct=='o': upperServoMiddle() elif direct=='p': upperServoRight() elif direct=='j': lowerServoLeft() elif direct=='k': lowerServoMiddle() elif direct=='l': lowerServoRight() elif direct=='c': camera.capture('group1.jpg') elif direct=='b': gpio.cleanup() bol=False elif direct=='v': camera.start_preview() sleep(15) camera.stop_preview() except KeyboardInterrupt: gpio.cleanup()
If you run the above script it will expect single-letter commands to control the tank. For example, the 'w' key will move forward, 's' will move backward, 'a' will go left etc. To exit from this script back to the terminal, use the 'b' key.
Finally, if you actually try replicating the setup describe so far, you'll notice that there are aspects of the power supply and servo control that don't work completely or need improvement, although this is a useful starting point.
Is it possible to build a remote-controlled Raspberry Pi streaming video tank for around $100. It may even be possible to bring the cost down even further by buying items in bulk, or purchasing cheaper breadboard kits which really only need to be purchased once if you want to make more than one.
The prototype presented in this article is by no means meant to represent a finished product, since there still issues with the power supply. It should instead be considered a snapshot of a unfinished work-in-progress.