Showing posts with label Servo. Show all posts
Showing posts with label Servo. Show all posts

Wednesday, February 27, 2013

USB Webcam on the Raspberry Pi

I wanted to use a USB webcam to mount on the robot, and drive it using the RPi. Turns out it is pretty simple to not only drive a USB webcam, but to also stream a MJPEG video feed over a port. After plugging the webcam in, we can check to see if the device is detected:


I run Arch on my RPi, which means installing things is super easy. Someone wrote up some software to do this streaming called mjpg-streamer.

$ sudo pacman -S mjpg-streamer

Once this installs the software is relatively simple to run. The options are defined as follows:

-d - USB Webcam (or video device)
-r - Resolution
-f - Frame Rate
-p - Port Number
-w -Web directory

An example of running the software:

$ mjpg_streamer -i "/usr/lib/input_uvc.so -d /dev/video0  -r 640x480 -f 28" -o "/usr/lib/output_http.so -p 8090 -w /var/www/mjpg_streamer"

This will send the stream over port 8090. Which can be accessed via URL through the following link (where alarmpi is the IP of the raspberry pi).

http://alarmpi:8090/?action=stream

This works with browsers which can read mjpg streams. If you happen have a web-controlled servo and some tape, you can embed the stream in the website and have a rotatable webcam.


Sunday, February 24, 2013

WebServo

I recently decided it would be fun to create a robot which I could control over the web (while at my office or wherever), which I could use to play with (torment) my cat Lilu. There are a few steps leading up to the creation of this. While I am waiting for the parts to arrive I started working on the web interface.

I am using an Arduino Uno as my micro controller to control the motors and servos which will be on the robot. I found ways to control the uno over the internet, however, they either require the purchase of a breakout board or USB connection to another computer. I own a couple Raspberry Pis and figured I could use what I had already to do the job. While (I think) it is totally possible to use just Arduino code to do all of this and use the RPi as the communication device, I found it more convenient given my level of understanding to simply use the RPi GPIO pins as switches for input to the Uno to trigger motor and servo control. Essentially the device will work as follows:

Web controlled robot from RPi and Uno

Since I am still (patiently) waiting for my parts. I will test my web based control using a single servo.

Raspberry GPIO control over the web

A man by the name of Eric wrote up this wonderful framework called WebIOPi, which allows for web-based GPIO control using a python-based server. The installation and usage of this framework is very simple and can be found on his site. The best part of this framework is the ability to customize the UI using the WebIOPi API.


WebIOPi Interface
I thought it would be rather neat to control the device using keyboard input. That is, the left arrow and right arrows will control the motion of the servo. I mapped each keyboard input to it's own RPi GPIO pin, so while the key is pressed the pin is high, and when released the pin is low. This was simple using some jQuery functions along with the WebIOPi API.

//Use webiopi object to initialize pins
   webiopi().read(function(){
//Init GPIO Pins 17 and 22 
     webiopi().setFunction(17,"OUT");
     webiopi().setFunction(22,"OUT");
   });

//Using the up(37) and down(39) arrows on pin 17,22.
//If key is pressed, pin goes high
   $(window).keydown(function(event){
     if(event.keyCode == 37) setValue(17,1);
     if(event.keyCode == 39) setValue(22,1);
   });
//If key is released, pin goes low
   $(window).keyup(function(event){
     if(event.keyCode == 37) setValueK(17,0);
     if(event.keyCode == 39) setValueK(22,0);
   });
//Use REST API to set pin value
   function setValueK(gpio, value){
     $.post('/GPIO/' + gpio + "/value/" + value, function(data){
            updateValue(gpio,value);                        
        });
   }
//Return data
   function updateValueK(gpio, value){
     var style = (value == 1) ? "HIGH" : "LOW";
     $("#gpio"+gpio).attr("class",style);
   }

Interface circuit for RPi and Arduino

I decided to keep the RPi and Arduino circuits isolated as I feel this would be the safest approach to combining them. This means that they each have their own power sources, which may mean the robot has a little more weight and costs a bit more, however, it means I won't have to figure out how to run it all off of one power source without frying everything. I used an opto-isolator (4n35) as a switch to provide the input for the Arduino. Using the following circuit, when the RPi pin goes high, the Arduino pin will go low. This can be detected in the Arduino code to control the servo.
Circuit diagram (apologies for the lack of standards I am no electrical engineer)

Arduino Sketch using RPi input

The Arduino sketch here is rather simple. If it detects pin 2 or 4 go low, then it will start to rotate the servo (which in this case is on pin 5). Pin 2 will rotate the servo in one direction, Pin 4 will rotate the sevro in the opposite direction.
#include <servo.h>

//Servo controller
Servo servoMain;

//Servo Definitions
int servoPin = 5;
int minP = 750;
int maxP = 2250;
int stepS = 3;
int delayTime = 20;

//Pin 2 definitions
int up = 2;
int valUp;
int bsUp;

//Pin 4 definitions
int down = 4;
int valDown;
int bsDown;

//Keep track of servo deg
int deg = 0;


void setup(){
//Init Pins
 pinMode(up, INPUT);
 pinMode(down, INPUT);

//Get inital reading
 bsUp = digitalRead(up); 
 bsDown = digitalRead(down); 

//Init servo
 servoMain.attach(servoPin,minP,maxP);
}

//Loop
void loop(){
 //Read pins
 valUp = digitalRead(up);
 valDown = digitalRead(down);

 //Only act if changed (reduce calculations)
 if ( (valUp != bsUp) || (valDown != bsDown) ){
 
  //If pin 2 is low, add the step to the servo
  if ( valUp == 0 ){
     deg += stepS;
     //Don't go past 180
     if( deg >= 180){
      deg = 180;
     }
     
     servoMain.write(deg); 
     delay(delayTime);
  }
  //If pin 4 is low, subtract the step from the servo
  if ( valDown == 0 ){
     deg -= stepS;
     //Don't go past 0
     if( deg <= 0){
       deg = 0;
     }
    
     servoMain.write(deg); 
     delay(delayTime);
  }
 }
}

Example:
      In this example I also added two buttons to the page for testing.