Things Used In This Project
- PHPoC Blue
- PHPoC Step Motor Controller II
- Stepper motor SE-SM243
- Jumper wires
Wiring Diagram
1. Stack Step motor controller II to PHPoC
2. Connecting to a bipolar stepper motor according to this instruction http://www.phpoc.com/support/manual/....php?id=layout
Source Codes
Main Task:
<task0.php>
PHP Code:
<?php
if(_SERVER("REQUEST_METHOD"))
exit; // avoid php execution via http request
include "/lib/sd_340.php";
include "/lib/sd_spc.php";
include "/lib/sn_tcp_ws.php";
define("STEPPER_SID", 14);
define("SPEED_LOW_LIMIT", 32);
define("SPEED_HIGH_LIMIT", 100000);
function step_loop()
{
$last_tick = st_free_get_count(0);
$rwbuf = "";
while(ws_state(0) == TCP_CONNECTED)
{
$rlen = ws_read_line(0, $rwbuf);
if($rlen)
{
$dur_ms = st_free_get_count(0) - $last_tick;
$last_tick = st_free_get_count(0);
$angle = -(float)$rwbuf;
$pos = (int)(200.0 * 32.0 * $angle / 360.0);
$step = $pos - (int)spc_request_dev(STEPPER_SID, "get pos");
if($step)
{
$speed = (int)abs((float)$step / (float)$dur_ms * 1000.0);
$speed = $speed * 8 / 10;
if($speed < SPEED_LOW_LIMIT)
$speed = SPEED_LOW_LIMIT;
else
if($speed > SPEED_HIGH_LIMIT)
$speed = SPEED_HIGH_LIMIT;
spc_request_dev(STEPPER_SID, "goto $pos $speed 1000k");
//echo "$step / $dur_ms $speed\r\n";
}
}
usleep(1000);
}
}
function ws_loop()
{
spc_request_dev(STEPPER_SID, "reset");
ws_setup(0, "spc_stepper_rotate", "csv.phpoc");
st_free_setup(0, "ms");
while(1)
{
if(ws_state(0) == TCP_CONNECTED)
{
$pos = (int)spc_request_dev(STEPPER_SID, "get pos");
$angle = -(float)$pos / (200.0 * 32.0) * 360.0;
ws_write(0, (string)$angle . "\r\n");
step_loop();
}
}
}
spc_reset();
spc_sync_baud(460800);
spc_request_dev(STEPPER_SID, "set vref drive 15");
spc_request_dev(STEPPER_SID, "set mode 32");
ws_loop();
?>
User Interface
<index.php>
PHP Code:
<!DOCTYPE html>
<html>
<head>
<title>PHPoC / <?echo system("uname -i")?></title>
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<style>
body { text-align: center; background-color: whiite;}
canvas { background-color: white; }
</style>
<script>
var MIN_TOUCH_RADIUS = 20;
var MAX_TOUCH_RADIUS = 200;
var CANVAS_WIDTH = 402, CANVAS_HEIGHT = 402;
var PIVOT_X = 201, PIVOT_Y = 201;
var plate_angle = 0;
var plate_img = new Image();
var click_state = 0;
var last_angle_pos = 0;
var mouse_xyra = {x:0, y:0, r:0.0, a:0.0};
var ws;
plate_img.src = "step_plate.png";
function init()
{
var stepper = document.getElementById("stepper");
stepper.width = CANVAS_WIDTH;
stepper.height = CANVAS_HEIGHT;
stepper.addEventListener("touchstart", mouse_down);
stepper.addEventListener("touchend", mouse_up);
stepper.addEventListener("touchmove", mouse_move);
stepper.addEventListener("mousedown", mouse_down);
stepper.addEventListener("mouseup", mouse_up);
stepper.addEventListener("mousemove", mouse_move);
var ctx = stepper.getContext("2d");
ctx.translate(PIVOT_X, PIVOT_Y);
rotate_plate(0);
ws = new WebSocket("ws://<?echo _SERVER("HTTP_HOST")?>/spc_stepper_rotate", "csv.phpoc");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = function(){ document.getElementById("ws_state").innerHTML = "OPEN" };
ws.onclose = function(){ document.getElementById("ws_state").innerHTML = "CLOSED"};
ws.onerror = function(){ alert("websocket error " + this.url) };
ws.onmessage = ws_onmessage;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
plate_angle = Number(e_msg.data);
rotate_plate(plate_angle);
//alert("msg : " + e_msg.data);
}
function rotate_plate(angle)
{
var stepper = document.getElementById("stepper");
var ctx = stepper.getContext("2d");
ctx.clearRect(-PIVOT_X, -PIVOT_Y, CANVAS_WIDTH, CANVAS_HEIGHT);
ctx.rotate(-angle / 180 * Math.PI);
ctx.drawImage(plate_img, -PIVOT_X, -PIVOT_Y);
ctx.rotate(angle / 180 * Math.PI);
debug = document.getElementById("debug");
debug.innerHTML = plate_angle.toFixed(1);
}
function check_update_xyra(event, mouse_xyra)
{
var x, y, r, a;
var min_r, max_r, width;
if(event.touches)
{
var touches = event.touches;
x = (touches[0].pageX - touches[0].target.offsetLeft) - PIVOT_X;
y = PIVOT_Y - (touches[0].pageY - touches[0].target.offsetTop);
}
else
{
x = event.offsetX - PIVOT_X;
y = PIVOT_Y - event.offsetY;
}
/* cartesian to polar coordinate conversion */
r = Math.sqrt(x * x + y * y);
a = Math.atan2(y, x);
mouse_xyra.x = x;
mouse_xyra.y = y;
mouse_xyra.r = r;
mouse_xyra.a = a;
if((r >= MIN_TOUCH_RADIUS) && (r <= MAX_TOUCH_RADIUS))
return true;
else
return false;
}
function mouse_down()
{
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
if(check_update_xyra(event, mouse_xyra))
{
click_state = 1;
last_angle_pos = mouse_xyra.a / Math.PI * 180.0;
}
}
function mouse_up()
{
click_state = 0;
}
function mouse_move()
{
var angle_pos, angle_offset;
if(event.touches && (event.touches.length > 1))
click_state = event.touches.length;
if(click_state > 1)
return;
if(!click_state)
return;
if(!check_update_xyra(event, mouse_xyra))
{
click_state = 0;
return;
}
angle_pos = mouse_xyra.a / Math.PI * 180.0;
if(angle_pos < 0.0)
angle_pos = angle_pos + 360.0;
angle_offset = angle_pos - last_angle_pos;
last_angle_pos = angle_pos;
if(angle_offset > 180.0)
angle_offset = -360.0 + angle_offset;
else
if(angle_offset < -180.0)
angle_offset = 360 + angle_offset;
plate_angle += angle_offset;
rotate_plate(plate_angle);
if(ws.readyState == 1)
ws.send(plate_angle.toFixed(4) + "\r\n");
event.preventDefault();
}
window.onload = init;
</script>
</head>
<body>
<h2>
Smart Expansion / Stepper Rotate<br>
<br>
<canvas id="stepper"></canvas>
<p>
WebSocket : <span id="ws_state">null</span><br>
Angle : <span id="debug">0</span>
</p>
</h2>
</body>
</html>