Robot Gripper Control through Internet using PHPoC Blue

Robot Gripper Control through Internet using PHPoC Blue

Postby Khanh » Mon Apr 18, 2016 9:48 am

Outline
    - Demo
    - Systems Architecture & Data flow
    - User Interface
    - Wiring between the gripper robot and PHPoC
    - Source Code
    - Code Explanation
1. Demo
phpBB [video]

2. Systems Architecture & Data flow

Systems Architecture
system_architecture.PNG
system_architecture.PNG (66.45 KiB) Viewed 1828 times

Data flow
data_flow.PNG
data_flow.PNG (37.8 KiB) Viewed 1828 times

3. User Interface
We have six actions: go forward, go backward, turn left, turn right, grip, release corresponding to six buttons.
ui.PNG
ui.PNG (41.42 KiB) Viewed 1828 times

4. Wiring between the gripper robot and PHPoC

There are three servo motors: one to control gripper and others to control two wheels. They are wired to PHPoC as below:
wiring.PNG
wiring.PNG (210.14 KiB) Viewed 1828 times

Getting power directly from PHPoC may be not enough, so it makes robot move slowly. If you want your robot run with full speed, provide extra power source for motors as follows:
wiring2.PNG
wiring2.PNG (147.79 KiB) Viewed 1828 times


5. Source Code
Apart from library, there are two main source files in PHPoC:
 index.php: once receiving http request from a client, PHPoC executes this file (only executing source inside <?php ?> tag) and then return a html file to client. So, client side is implemented in this file.
 task0.php: this file contains the source code of server side. So you can implement the function to receive the command and control the robot here.

[Source code - index.php]
Code: Select all

<?php
    $ws_host 
= _SERVER("HTTP_HOST");
    define("CMD_STOP", 0);
    define("CMD_FORWARD", 1);
    define("CMD_BACKWARD", 2);
    define("CMD_LEFT", 4);
    define("CMD_RIGHT", 8);
    define("CMD_GRIP", 16);
    define("CMD_RELEASE", 32);
?>
<!DOCTYPE html>
<html>
<head>
<title>PHPoC Robot Gripper</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style type="text/css">
body { text-align: center; }
#container {
    margin-right: auto;
    margin-left: auto;
    width: 1024px; 
    height: 768px; 
    background: url(background.png) no-repeat; 
    background-size: contain;
    position: relative;
    margin-bottom: 10px;
    border: 1px solid #000;
}
div[class^='arrow'] { position: absolute; }
.arrow_up, .arrow_down { width:214px; height:104px;}
.arrow_left, .arrow_right { width:104px; height:214px;}
.arrow_grip, .arrow_release { width:88px; height:178px;}
.arrow_up {
    background: url(up_inactive.png) no-repeat; 
    background-size: contain; 
    left: 405px;
    top: 176px;
}

.arrow_down {
    background: url(down_inactive.png) no-repeat; 
    background-size: contain; 
    left:405px;
    top:488px;
}

.arrow_right {
    background: url(right_inactive.png) no-repeat;
    background-size: contain;     
    left:615px;
    top:277px;
}

.arrow_left {
    background: url(left_inactive.png) no-repeat; 
    background-size: contain;
    left:305px;
    top:277px;
}

.arrow_grip {
    background: url(grip_inactive.png) no-repeat; 
    background-size: contain;
    left:424px; top:295px;
}
.arrow_release {
    background: url(release_inactive.png) no-repeat; 
    background-size: contain;
    left:512px; top:295px;
}

</style>
<script type="text/javascript">
var CMD_STOP = 0;
var img_name_lookup = {
    <?php echo CMD_FORWARD?>: "up",
    <?php echo CMD_BACKWARD?>: "down",
    <?php echo CMD_LEFT?>: "left",
    <?php echo CMD_RIGHT?>: "right",
    <?php echo CMD_GRIP?>: "grip",
    <?php echo CMD_RELEASE?>: "release",
}
var ws = null;

function init() 
{
    
    var container = document.querySelector("#container");
    container.addEventListener("touchstart", mouse_down);
    container.addEventListener("touchend", mouse_up);
    container.addEventListener("touchcancel", mouse_up);
    container.addEventListener("mousedown", mouse_down);
    container.addEventListener("mouseup", mouse_up);
    container.addEventListener("mouseout", mouse_up);    
}
function ws_onmessage(e_msg)
{
    e_msg = e_msg || window.event; // MessageEvent
 
    //alert("msg : " + e_msg.data);
}
function ws_onopen()
{
    document.getElementById("ws_state").innerHTML = "OPEN";
    document.getElementById("wc_conn").innerHTML = "Disconnect";
}
function ws_onclose()
{
    document.getElementById("ws_state").innerHTML = "CLOSED";
    document.getElementById("wc_conn").innerHTML = "Connect";
    console.log("socket was closed");
    ws.onopen = null;
    ws.onclose = null;
    ws.onmessage = null;
    ws = null;
}
function wc_onclick()
{
    if(ws == null)
    {
        ws = new WebSocket("ws://<?echo $ws_host?>/robot_gripper", "csv.phpoc");
        document.getElementById("ws_state").innerHTML = "CONNECTING";
        
        ws.onopen = ws_onopen;
        ws.onclose = ws_onclose;
        ws.onmessage = ws_onmessage; 
    }
    else
        ws.close();
}
function mouse_down(event) 
{
    if (event.target !== event.currentTarget) 
    {
        var id = event.target.id;
        send_command(id);
        event.target.style.backgroundImage = "url('" + img_name_lookup[id] + "_active.png')";
    }
    event.stopPropagation();    
    event.preventDefault();    
}

function mouse_up(event) 
{
    if (event.target !== event.currentTarget) 
    {
        var id = event.target.id;
        send_command(CMD_STOP);
        event.target.style.backgroundImage = "url('" + img_name_lookup[id] + "_inactive.png')";
    }
    event.stopPropagation();   
    event.preventDefault();    
}
function send_command(cmd) 
{   
    if(ws != null)
        if(ws.readyState == 1)
            ws.send(cmd + "\r\n");   
}

window.onload = init;
</script>
</head>
<body>

<div id="container">
    <div id="<?echo CMD_FORWARD?>" class="arrow_up"></div>
    <div id="<?echo CMD_BACKWARD?>" class="arrow_down"></div>
    <div id="<?echo CMD_RIGHT?>" class="arrow_right"></div>
    <div id="<?echo CMD_LEFT?>" class="arrow_left"></div>
    <div id="<?echo CMD_GRIP?>" class="arrow_grip"></div>
    <div id="<?echo CMD_RELEASE?>" class="arrow_release"></div>
</div>
<p>
WebSocket : <span id="ws_state">null</span><br>
</p>
<button id="wc_conn" type="button" onclick="wc_onclick();">Connect</button>
</body>
</html>

[Source code - task0.php]
Code: Select all

 <?php

if(_SERVER("REQUEST_METHOD"))
    exit; // avoid php execution via http request

include "/lib/sd_340.php";
include "/lib/sn_tcp_ws.php";

define("GRIP_SRV_PERIOD", 20000); // 20000us (20ms)
define("GRIP_SRV_WIDTH_MIN", 600);
define("GRIP_SRV_WIDTH_MAX", 2450);

define("WHL_SRV_CLK", 1300);
define("WHL_SRV_STOP", 1500); 
define
("WHL_SRV_ANT_CLK", 1700);
define("WHL_SRV_PERIOD", 20000);

define("CMD_STOP", 0);
define("CMD_FORWARD", 1);
define("CMD_BACKWARD", 2);
define("CMD_LEFT", 4);
define("CMD_RIGHT", 8);
define("CMD_GRIP", 16);
define("CMD_RELEASE", 32);

define("HT_GRIP", 0);// ht0 control gripper (standard servo)
define("HT_LEFT", 1);// ht1 control the left wheel (continuous rotation servo)
define("HT_RIGHT", 2);// ht2 control the right wheel (continuous rotation servo)

$angle_max = 145;
$angle_min = 0;
$angle = 20;
$step = 1;
$grip_state = 0;

function servo_clockwise($id) 
{
    ht_pwm_width($id, WHL_SRV_CLK, WHL_SRV_CLK + WHL_SRV_PERIOD);
}

function servo_anti_clockwise($id) 
{
    ht_pwm_width($id, WHL_SRV_ANT_CLK, WHL_SRV_ANT_CLK + WHL_SRV_PERIOD);
}

function servo_stop($id) 
{
    ht_pwm_width($id, WHL_SRV_STOP, WHL_SRV_STOP + WHL_SRV_PERIOD);
}


function servo_set_angle($angle) 
{             
    $width 
= GRIP_SRV_WIDTH_MIN + (int)round((GRIP_SRV_WIDTH_MAX - GRIP_SRV_WIDTH_MIN) * $angle / 180.0);
    if(($width >= GRIP_SRV_WIDTH_MIN) && ($width <= GRIP_SRV_WIDTH_MAX))
        ht_pwm_width(HT_GRIP, $width, GRIP_SRV_PERIOD);
}

ht_pwm_setup(HT_GRIP, (GRIP_SRV_WIDTH_MIN + GRIP_SRV_WIDTH_MAX) / 2, GRIP_SRV_PERIOD, "us");
ht_pwm_setup(HT_RIGHT, WHL_SRV_STOP, WHL_SRV_STOP + WHL_SRV_PERIOD, "us");
ht_pwm_setup(HT_LEFT, WHL_SRV_STOP, WHL_SRV_STOP + WHL_SRV_PERIOD, "us");
ws_setup(0, "robot_gripper", "csv.phpoc");

servo_set_angle($angle);
$rbuf = "";
 
while(1)
{
    
    if
(ws_state(0) == TCP_CONNECTED)
    {
        $rlen = ws_read_line(0, $rbuf);

        if($rlen)
        {
            $cmd = (int)$rbuf;
            switch($cmd)
            {                     
                case CMD_FORWARD
:  
                    servo_anti_clockwise
(HT_LEFT);
                    servo_clockwise(HT_RIGHT); 
                    break
;  
                case CMD_BACKWARD
:  
                    servo_clockwise
(HT_LEFT);
                    servo_anti_clockwise(HT_RIGHT);
                    break;  
                case CMD_LEFT
:  
                    servo_stop
(HT_LEFT);
                    servo_clockwise(HT_RIGHT); 
                    break
;  
                case CMD_RIGHT
:  
                    servo_anti_clockwise
(HT_LEFT);
                    servo_stop(HT_RIGHT); 
                    break
;  
                case CMD_GRIP
:  
                    $grip_state 
= -1;
                    break;
                case CMD_RELEASE:  
                    $grip_state 
= 1;
                    break;
                default:
                    servo_stop(HT_LEFT);
                    servo_stop(HT_RIGHT);
                    $grip_state = 0;
            }
            
        
}
        if($grip_state != 0)
        {
            $angle += $grip_state*$step;
            if($angle > $angle_max)
                $angle = $angle_max;
            else if($angle < $angle_min)
                $angle = $angle_min;
            // set angle 
            servo_set_angle($angle);
        }
    }
}
 
?>
   

6. Code Explanation
Client side:
There six buttons corresponding to six commands:
In both index.php and task0.php files, I define:
Code: Select all
   define("CMD_STOP", 0);
   define("CMD_FORWARD", 1);
   define("CMD_BACKWARD", 2);
   define("CMD_LEFT", 4);
   define("CMD_RIGHT", 8);
   define("CMD_GRIP", 16);
   define("CMD_RELEASE", 32);
      

in index.php file:
Code: Select all
<div id="container">
    <div id="<?echo CMD_FORWARD?>" class="arrow_up"></div>
    <div id="<?echo CMD_BACKWARD?>" class="arrow_down"></div>
    <div id="<?echo CMD_RIGHT?>" class="arrow_right"></div>
    <div id="<?echo CMD_LEFT?>" class="arrow_left"></div>
   <div id="<?echo CMD_GRIP?>" class="arrow_grip"></div>
   <div id="<?echo CMD_RELEASE?>" class="arrow_release"></div>
</div>
      

To set event hander for all buttons, I use a small tip here:
Code: Select all
   var action = document.querySelector("#container");
    action.addEventListener("touchstart", mouse_down);
    action.addEventListener("touchend", mouse_up);
    action.addEventListener("touchcancel", mouse_up);
    action.addEventListener("mousedown", mouse_down);
    action.addEventListener("mouseup", mouse_up);
    action.addEventListener("mouseout", mouse_up);
      

I don’t need to add event listener for all buttons, just add event handler for their parent.
And in event handler, just do:
Code: Select all
   if (event.target !== event.currentTarget) {
      // do something here basing on event.target.id
    }
    event.stopPropagation();   
    event.preventDefault();
      

When an event occurs:
- Send command to PHPoC through websocket
- Switch image between active and inactive.
To avoid using switch and case for six commands:
- Id of button is command id, so just send “event.target.id” to PHPoC
- To switch images, I use a lookup table:
Code: Select all
   var img_name_lookup = {
      <?php echo CMD_FORWARD?>: "up",
      <?php echo CMD_BACKWARD?>: "down",
      <?php echo CMD_LEFT?>: "left",
      <?php echo CMD_RIGHT?>: "right",
      <?php echo CMD_GRIP?>: "grip",
      <?php echo CMD_RELEASE?>: "release",
   }
      

Changing images basing on “event.target.id”:
Code: Select all
   event.target.style.backgroundImage = "url('" + img_name_lookup[event.target.id] + "_active.png')";
      

or
Code: Select all
   event.target.style.backgroundImage = "url('" + img_name_lookup[event.target.id] + "_inactive.png')";
      

Without using switch case, we can reduce size of code.
Server side:
PWM pulses are used to control servo motors. There are a standard servo and two continuous servo motors.
- Standard servo motor: rotates from 0 to 180 degree used to rotate gripper.
- Continuous servo motors: continuously rotate in clockwise or anti-clockwise direction used to rotate two wheels.
With a value of pulse width:
- Standard motor: rotate to an angle corresponding to that value and then stop.
- Continuous motor: keep rotating with a speed corresponding to that value.
motor.PNG
motor.PNG (12.7 KiB) Viewed 1828 times

PHPoC take action basing on command from user.
table.PNG
table.PNG (13.53 KiB) Viewed 1828 times

For gripper motor, it is moved gradually by repeating: move a small step, pause a small time.
For each step, new angle is calculated by:
$angle += $grip_state*$step;
Direction of gripper motor is based on gripper state value:
- 0: angle keeps unchanged (stop).
- 1: angle is incremented by value of step (release).
- -1: angle is decremented by value of step (grip)
You can download full source code here:
PHPoC_robot_gripper.rar
(365.74 KiB) Downloaded 137 times
Khanh
 
Posts: 69
Joined: Fri Mar 11, 2016 10:57 am

Return to Project

Who is online

Users browsing this forum: No registered users and 1 guest

cron