<!DOCTYPE html>
<html>
<head>
<title>PHPoC - Arm Robot</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body { text-align: center; }
canvas { background-color: #f0f0f0; }
</style>
<script>
var MOTOR_1 = 0;
var MOTOR_2 = 1;
var MOTOR_3 = 2;
var MOTOR_4 = 3;
var MOTOR_5 = 4;
var MOTOR_6 = 5;
var canvas_width = 900, canvas_height = 600;
var sole_width = 160, sole_height = 75;
var pivot_x = canvas_width / 2, pivot_y = canvas_height - sole_height;
var arm_length_1 = 95,
arm_length_2 = 88,
arm_length_3 = 155;
var zone_A_radius = arm_length_1 + arm_length_2 + arm_length_3;
var zone_B_radius_in = zone_A_radius + 10;
var zone_B_radius_out = zone_B_radius_in + 60;
var zone_D_width = 200, zone_D_height = 30;
var zone_D_left = pivot_x - zone_D_width - 40;
var zone_D_top = pivot_y - zone_D_height - 50;
var zone_C_center_x = -pivot_x + 100;
var zone_C_center_y = pivot_y - 100;
var zone_C_radius_in = 30, zone_C_radius_out = 60;
var grip_max_angle = 62; // 62 degree
var click_state = 0;
var mouse_xyra = {x:0, y:0, r:0.0, a:0.0};
var angles = [20, 120, 120, 120, 30, 50];
var ws = null;
var servo = null, ctx = null;
var last_time;
var a = 0, b = 0, c = 0;
function init()
{
servo = document.getElementById("servo");
servo.width = canvas_width;
servo.height = canvas_height;
servo.addEventListener("touchstart", mouse_down);
servo.addEventListener("touchend", mouse_up);
servo.addEventListener("touchmove", mouse_move);
servo.addEventListener("mousedown", mouse_down);
servo.addEventListener("mouseup", mouse_up);
servo.addEventListener("mousemove", mouse_move);
ctx = servo.getContext("2d");
ctx.translate(pivot_x, pivot_y);
ctx.rotate(Math.PI);
ctx.strokeStyle="#00a3cc";
ctx.lineWidth = 4;
// quadratic equation parameters
a = 4*arm_length_1*arm_length_3;
b = 2*(arm_length_2*arm_length_1 + arm_length_2*arm_length_3);
c = Math.pow(arm_length_1, 2) + Math.pow(arm_length_2, 2) + Math.pow(arm_length_3, 2) - 2*arm_length_1*arm_length_3;
}
function update_view()
{
ctx.clearRect(-canvas_width/2, -sole_height, canvas_width, canvas_height);
ctx.fillStyle = "#00ccff";
ctx.save();
//draw zone A
ctx.beginPath();
ctx.arc(0,0,zone_A_radius, 0, 2*Math.PI);
ctx.stroke();
// draw zone B
ctx.strokeStyle="#ff8080";
var angle = angles[0] * Math.PI / 180;
ctx.beginPath();
ctx.arc(0, 0, zone_B_radius_out, 0, angle);
ctx.arc(0, 0, zone_B_radius_in, angle, 0, true);
ctx.fill();
ctx.beginPath();
ctx.arc(0, 0, zone_B_radius_out, 0, Math.PI);
ctx.arc(0, 0, zone_B_radius_in, Math.PI, 0, true);
ctx.closePath();
ctx.stroke();
// draw zone C
angle = angles[MOTOR_5] * Math.PI / 180;
ctx.beginPath();
ctx.arc(zone_C_center_x, zone_C_center_y, zone_C_radius_out, 0, angle);
ctx.arc(zone_C_center_x, zone_C_center_y, zone_C_radius_in, angle, 0, true);
ctx.fill();
ctx.beginPath();
ctx.arc(zone_C_center_x, zone_C_center_y, zone_C_radius_out, 0, Math.PI);
ctx.arc(zone_C_center_x, zone_C_center_y, zone_C_radius_in, Math.PI, 0, true);
ctx.closePath();
ctx.stroke();
// draw zone D
var temp = Math.floor(angles[MOTOR_6] / grip_max_angle * 200);
ctx.fillRect(zone_D_left, zone_D_top, temp, zone_D_height);
ctx.rect(zone_D_left, zone_D_top, zone_D_width, zone_D_height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(zone_D_left, zone_D_top + zone_D_height / 2);
ctx.arc(zone_D_left, zone_D_top + zone_D_height / 2, zone_D_height, Math.PI / 2, Math.PI * 3 / 2);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(zone_D_left + temp, zone_D_top + zone_D_height / 2);
ctx.arc(zone_D_left + temp, zone_D_top + zone_D_height / 2, zone_D_height, Math.PI / 2, Math.PI * 3 / 2, true);
ctx.closePath();
ctx.fill();
// draw arm segments
ctx.lineWidth = 6;
ctx.rotate(angles[MOTOR_2] / 180 * Math.PI);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(arm_length_1,0);
ctx.stroke();
draw_pivot(0, 0);
ctx.translate(arm_length_1,0);
ctx.rotate(-Math.PI + angles[MOTOR_3] / 180 * Math.PI);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(arm_length_2, 0);
ctx.stroke();
draw_pivot(0, 0);
ctx.translate(arm_length_2,0);
ctx.rotate(-Math.PI + angles[MOTOR_4] / 180 * Math.PI);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(arm_length_3, 0);
ctx.stroke();
draw_pivot(0, 0);
ctx.restore();
// draw sole
ctx.fillStyle = "#818181";
ctx.fillRect(-sole_width/2, -sole_height, sole_width, sole_height);
}
function event_handler(event)
{
var x, y, r, alpha;
// convert coordinate
if(event.touches)
{
var touches = event.touches;
x = (touches[0].pageX - touches[0].target.offsetLeft) - pivot_x;
y = (touches[0].pageY - touches[0].target.offsetTop) - pivot_y;
}
else
{
x = event.offsetX - pivot_x;
y = event.offsetY - pivot_y;
}
x = -x;
y = -y;
//check whether it's located in zone D or not
var temp_x = x - zone_D_left;
var temp_y = y - zone_D_top;
//if(temp_x > 0 && temp_x < zone_D_width && temp_y > 0 && temp_y < zone_D_height)
if(temp_x > -zone_D_height && temp_x < (zone_D_width + zone_D_height) && temp_y > 0 && temp_y < zone_D_height)
{
if(temp_x < 0)
temp_x = 0;
else if(temp_x > zone_D_width)
temp_x = zone_D_width;
var angle = temp_x / zone_D_width * grip_max_angle;
angles[MOTOR_6] = Math.floor(angle);
return true;
}
//check whether it's located in zone C or not
temp_x = x - zone_C_center_x;
temp_y = y - zone_C_center_y;
var distance = Math.sqrt(temp_x * temp_x + temp_y * temp_y);
if(distance > zone_C_radius_in && distance < zone_C_radius_out && y > zone_C_center_y)
{
var angle = Math.atan2(temp_y, temp_x)* 180 / Math.PI;
angles[MOTOR_5] = Math.floor(angle);
return true;
}
//check whether it's located in zone B or not
r = Math.sqrt(x * x + y * y);
if(r > zone_B_radius_out)
return false;
if(r > zone_B_radius_in && y < 0)
return false;
if(r > zone_B_radius_in)
{
var angle = Math.atan2(y, x)* 180 / Math.PI;
angles[MOTOR_1] = Math.floor(angle);
return true;
}
//check whether it's located in zone A or not
if(r > zone_A_radius)
return false;
if(y < -sole_height)
return false;
if((x < sole_width/2) && (x > -sole_width/2) && (y < 0))
return false;
alpha = Math.atan2(y, x);
if(alpha < 0)
alpha += 2*Math.PI;
mouse_xyra.x = x;
mouse_xyra.y = y;
mouse_xyra.r = r;
mouse_xyra.a = alpha;
if(geometric_calculation())
return true;
return false;
}
function geometric_calculation()
{
var c_ = c - Math.pow(mouse_xyra.r, 2);
var delta = b*b - 4*a*c_;
if(delta < 0)
return false; // no root
var x1 = 0, x2 = 0;
var x = 0;
var cos_C = 0;
var alpha = 0, beta = 0, gamma = 0;
x1 = (-b + Math.sqrt(delta)) / (2*a);
x2 = (-b - Math.sqrt(delta)) / (2*a);
x = x1;
if(x > 1)
return false;
alpha = Math.acos(x);
alpha = alpha * 180 / Math.PI;
beta = 180 - alpha;
cos_C = Math.pow(mouse_xyra.r, 2) + Math.pow(arm_length_1, 2) - ( Math.pow(arm_length_2, 2) + Math.pow(arm_length_3, 2) + 2*arm_length_2*arm_length_3*x );
cos_C = cos_C /(2*mouse_xyra.r*arm_length_1);
angle_C = Math.acos(cos_C);
gamma = (angle_C + mouse_xyra.a) % (2*Math.PI);
gamma = gamma * 180 / Math.PI;
if(gamma < 0)
gamma += 360;
if(gamma > 180)
{
var temp = gamma - mouse_xyra.a * 180 / Math.PI;
gamma = gamma - 2* temp;
beta = 360 - beta;
}
if(gamma < 0 || gamma > 180)
return false;
angles[MOTOR_3] = Math.floor(beta);
angles[MOTOR_4] = Math.floor(beta);
angles[MOTOR_2] = Math.floor(gamma);
return true;
}
function draw_pivot(x, y)
{
ctx.beginPath();
ctx.arc(x,y, 5, 0, 2*Math.PI);
ctx.stroke();
}
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";
if(ws.readyState == 1)
ws.send(angles.join(" ") + "\r\n");
update_view();
}
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 _SERVER("HTTP_HOST")?>/robot_arm", "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()
{
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
var state = event_handler(event);
if(state)
{
click_state = 1;
angles_change_notice();
}
event.preventDefault();
}
function mouse_up()
{
click_state = 0;
}
function mouse_move()
{
var d = new Date();
var time = d.getTime();
if((time - last_time) < 50)
return;
last_time = time;
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
if(!click_state)
return;
var state = event_handler(event);
if(state)
{
click_state = 1;
angles_change_notice();
}
event.preventDefault();
}
function angles_change_notice()
{
if(ws != null)
if(ws.readyState == 1)
{
ws.send(angles.join(" ") + "\r\n");
update_view();
}
}
window.onload = init;
//update_view();
setTimeout(function(){ update_view();}, 500);
</script>
</head>
<body>
<h2>
Arm Robot<br>
</h2>
<br>
<canvas id="servo"></canvas>
<p>
WebSocket : <span id="ws_state">null</span><br>
</p>
<button id="wc_conn" type="button" onclick="wc_onclick();">Connect</button>
</body>
</html>
Comments