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.




5 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Excellent tutorial. I only have a question: where did you write the jScript code above? in what file? Thank you.

    ReplyDelete
    Replies
    1. In the html file. Check out the WebIO demo to see their format. I basically just adjusted what they had.

      Delete
    2. Did you do any modification to the py file? Whatever I do, it does not seem to work.

      Delete
  3. can you please upload your code from your finished html file. I am trying to rewrite the light switch tutorials html file and insert your but its just showing a blank page without any gpio activity.

    ReplyDelete