DIY蓝牙模块+processing互动型绘图机械臂(arduino)
江头钓宝宝宝宝
看过论坛里好多大神DIY的绘图机感觉十分过瘾,于是自己也下决心做一个。其实网上关于绘图机的实现方法有很多,有用步进电机的,有用丝杆的,不过这些对于一个初入arduino小菜鸟来说还是有点困难的。于是我打算用最容易实现的方法:鼠标画图,processing通过蓝牙传输坐标信号,arduino接受信号并计算角度,舵机函数直接写角度实现绘图。
下图是DIY所需材料:控制器Arduino UNO
标准舵机2×PDI-6221MG-180°(大扭力)
多功能支架2(固定舵机用)
长U型架4
短U型架3
杜邦线公对母4
杜邦线公对公10
蓝牙模块HC-05
好了不废话了,下面进入正题。
一.机械部分
首先我们需要搭建起一个霸气的机械手臂,同学们请准备好足量的螺丝和螺母。多功能支架用来固定舵机,剩下的发挥自己的想象力完全可以自己拼的,要不怎么说是DIY呢?两个舵机自然要有两节手臂部分了,为了之后好说明我把它们分别命名为肩部舵机和肘部舵机。这两部分的长度可以自己定的,不过最好不要太长会存在支撑的问题。除此之外,一件必不可少的工作就是找一把尺子尽量精确的测出肩部和肘部的长度(这里指实际参与转动的长度)。这很重要的是要写入程序的。
二.建模部分
在这里我们其实有三个已知量鼠标的坐标,肩部长度r1,肘部长度r2.
α为肩部舵机的角度,β为肘部舵机的角度,P点为鼠标所在位置。通过直线OP,由 可以求出OP与X轴夹角,同时在三角形内部根据余弦函数容易得出∠AOP。此时α=180-〖tan〗^(-1)〖y/x〗-∠AOP,如此我们就得到了可以写入舵机的两个角度。由于这里本宝宝偷懒了一下,只使用了两个舵机(也就是说没有控制落笔的舵机,既笔固定在肘部关节末端)这时只要有信号就会画出相应的图形,这就要求该图形必须是封闭的(要画只能连续画)。呵呵,小瑕疵,大家别学我。
三.数据传输
这次的DIY宝宝用到了HC-05蓝牙透传模块,并第一次尝试arduino自带的软件串口库模拟了一个串口(实在是UNO只有一个硬件串口,你下载程序还必须用它)。好了进入正题,首先宝宝打算传输Processing中的x坐标和y坐标。这两个数据都是两字节的int型数据,宝宝把它们分别除以256,分成两个一字节的数据。
再将这四个字节按顺序发送出去,这样其实还不保险于是我加了‘H’和‘M’两个字符作为头字符来进行校验。这样一个数据包一共6个字节,下面是发送代码和接受部分的代码:
/*processing*/
void jisuan(char tag,intx,int y)
{
myport.write(HEADER); /发送头字符/
myport.write(tag);
myport.write((char)(x/256)); /发送X坐标/
myport.write( x&0xff);
myport.write((char)(y/256)); /发送Y坐标/
myport.write(y&0xff);
}
/*arduino*/
if(BT.available()>=TOTAL) /这里TOTAl=6,判断是否接受一个包/
{
if(BT.read()==HEADER) /判断头字符/
{
char tag=BT.read();
if(tag==MOUSE_TAG)
{
int x=BT.read()*256; /接受并还原X,Y坐标/
x=x+BT.read();
int y=BT.read()*256;
y=y+BT.read();
四. 程序设计
arduino
#include
#include
floatj,z,r1=100.0,r2=190.0;
const char HEADER='H';
const char MOUSE_TAG='M';
const int TOTAL=6;
SoftwareSerial BT(10,9);
Servo jianbu;
Servo zhoubu;
Servo luobi;
void setup()
{
jianbu.attach(5,500,2500);
zhoubu.attach(6,500,2500);
luobi.attach(7,500,2500);
BT.begin(9600);
BT.print("BT is ready! ");
delay(50);
jianbu.write(0);
zhoubu.write(0);
}
void loop()
{
if(BT.available()>=TOTAL)
{
if(BT.read()==HEADER)
{
char tag=BT.read();
if(tag==MOUSE_TAG)
{
int x=BT.read()*256;
x=x+BT.read();
int y=BT.read()*256;
y=y+BT.read();
jisuan(x,y);
jianbu.write(j);
zhoubu.write(z);
delay(50);
}
else
{
BT.print("you are foolish");
BT.write(tag);
}
}
}
delay(50);
}
float jisuan(int x,int y)
{
x=x-300;
float p=sqrt(x*x+y*y);
float a=acos((r1*r1+p*p-r2*r2)/(2*r1*p));
float b=acos((r2*r2+p*p-r1*r1)/(2*r2*p));
z=degrees(a+b);
j=180-degrees(atan2(y,x))-degrees(a);
j=floor(j);
z=floor(z);
if((j>=0&&j<=180)&&(z>=0&&z<=180))
return j,z;
}
Processing
importprocessing.serial.*;
Serial myport;
public static final charHEADER='H';
public static final charMOUSE_TAG='M';
void setup()
{
String portName=Serial.list()[1];
myport=new Serial(this,portName,9600);
size(600,400);
strokeWeight(5);
point(300,0);
}
void draw()
{
}
void mouseDragged()
{
jisuan(MOUSE_TAG,mouseX,mouseY);
line(pmouseX,pmouseY,mouseX,mouseY);
delay(50);
}
void jisuan(char tag,intx,int y)
{
myport.write(HEADER);
myport.write(tag);
myport.write((char)(x/256));
myport.write( x&0xff);
myport.write((char)(y/256));
myport.write(y&0xff);
}