EVILMAKER INTEL EDISON 全自动刀路转换 高速激光雕刻机


克里斯安德森在《创客》一书中写到,创客有四大基本工具,CNC,3D扫描仪,3D打印机和激光雕刻机,前三者已经趋于普及,唯独桌面级激光雕刻机却始终处于初级阶段。

这一次,我们革新了以往的用户体验,将传统的电脑端生成刀路,送入雕刻机雕刻的过程完全简化,加入此端拍照,彼端自动开始雕刻的黑科技,采用Intel Edison平台+OpenCV视觉运算来实现TP、OpenCV自动处理、全自动生成刀路以及输送至我们的雕刻机完成相应的自动调焦雕刻工作。


我们在Edison上通过预编译的Ubuntu系统来作为OpenCV的运行平台,使用脚本调用完成我们的预定目标。

输入一张唯美的相片,轻击雕刻即可享受一键转换带来的轻松写意的用户体验。

而现在,我们带来了全新的高速激光雕刻机,采用Delta急速并联臂架构,自动对焦,配有全自动刀路生成程式,雕刻速度相比其他同级别架构提升10-20倍,令以往繁杂的激光雕刻准备工作变得轻松写意,飞掣凛然,使得桌面级激光雕刻机成为可能。


我们团队曾参与多款国内顶级桌面级激光雕刻方案研发,在以往开发的精准架构CoreXY,H-Bot等驱动方案基础上加以革新,借此次中美Maker创意爆炸为契机,开发了这款以速度便捷为核心方向的机器,并且匹配有普通Delta以及其他3D打印机的改造方案,每个人都可以在自己的3D打印机基础上加装我们的设备方案使其变为高速桌面级激光雕刻机,让创意在Maker手中更加具现化,游刃有余。


如何让您的Edison开发进阶应用呢?下面就已本项目为例大致介绍一下技术细节。

首先,intel Edison 是一块功能相当强大的开发板,其综合性能远超市面上的开发板,所以非常适合用来做进阶开发和图形处理,无论是存储性能还是X86架构都表现比树莓派之类的开发板优异,而现在大多数人把Edison作为Arduino来使用,也就是所谓的Edison as Arduino,这是非常浪费的事情。所以我更推荐把Edsion作为Liunx开发板来使用。

Edison自带了自主改进的Unix系统,当然有时候可能会出现不兼容其他系统应用的问题,所以我们把Edison装载了Ubuntu系统,这样可以兼容大部分应用程序,并且可以通过安装X-Windows以及连接CSK大大的USB显示器来实现图形化操作Edison,如下图所示,就是安装了Ubuntu以及连接了RoboPeak USB Display的演示。


首先需要一张容量大于16GB的TF卡,在电脑上使用LINUX虚拟机或者LINUX主机,随后在系统终端以SU权限查看挂载信息并将TF卡格式化为EXT4格式。

sudo fdisk -lu
sudo fdisk /dev/sdb
sudo mkfs -t ext4 /dev/sdb

将预编译的系统镜像写入TF卡,并进入Edison终端设置从TF卡启动系统即可完成环境配置。

fw_setenv myrootfs_emmc 'PARTUUID=012b3303-34ac-284d-99b4-34e03a2335f4'
fw_setenv myrootfs '/dev/mmcblk1p1'
fw_setenv do_boot_emmc 'setenv myrootfs ${myrootfs_emmc}; run do_boot'
fw_setenv do_boot_sdcard 'setenv myrootfs ${myrootfs_sdcard}; run do_boot'

随后在安装好的Ubuntu平台上安装OpenCV所需的各个基本包,当然也需要预装一些运行库,如下:

sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg62-dev libtiff4-dev cmake libswscale-dev libjasper-dev

随后就可以和开发普通Linux设备一样进行其他的开发,以下放出部分我们早期的图形处理算法,仅供作为例程参考:

#include
#include
#include
#include
#include

using namespace std;
using namespace cv;
int main(int argc,char *argv[])
{
int camera_id = 0;
ofstream outfile;
outfile.open("Gcode.txt");

if(argc>1)
{
camera_id = atoi(argv[1]);
}

cv::VideoCapture cap(camera_id);
if(!cap.isOpened())
{
printf("failed to open the camera with id %d.\n",camera_id);
return -1;
}
cv::Mat frame;
cap>>frame;
imwrite("camera_captured.png",frame);

//Mat img = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
Mat edges;
cvtColor(frame, edges, CV_BGR2GRAY);
//blur(edges,edges,Size(3,3));
//Canny(edges,edges,50,100,3);

/* MatIterator_ grayit, grayend;
for(grayit = edges.begin(),grayend = edges.end(); grayit != grayend; ++grayit)
{
if(*grayit==255)
{
*grayit = 0;
}
else
{
*grayit = 255;
}
//outfile }*/

//Mat roi(edges, Rect(10,10,100,100));

/*
640*480
*/

Mat roi(edges,Rect(0,0,640,480));

/*
255:
G1 X10 Y10(移动到起始位置)
M106(开启激光)
G1 X10 Y30(雕刻从10-30之间的路径)
M107(关闭激光)
G1 X10 Y40(移动到下一个位置)
M106
G1 X10 Y50
M107

*/
/*******************************************************/

#define GrayScale 255 //frame 灰度级
int width = roi.cols;
int height = roi.rows;
int pixelCount[GrayScale]={0};
float pixelPro[GrayScale]={0};
int pixelSum = width * height, threshold = 0;
uchar* data = (uchar*)roi.ptr();

//统计每个灰度级中像素的个数
for(int i = 0; i {
for(int j = 0;j {
pixelCount[(int)data[i * width + j]]++;
}
}

//计算每个灰度级的像素数目占整幅图像的比例
for(int i = 0; i {
pixelPro[i] = (float)pixelCount[i] / pixelSum;
}

//遍历灰度级[0,255],寻找合适的threshold
float w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0;
for(int i = 0; i {
w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;
for(int j = 0; j {
if(j {
w0 += pixelPro[j];
u0tmp += j * pixelPro[j];
}
else //前景部分
{
w1 += pixelPro[j];
u1tmp += j * pixelPro[j];
}
}
u0 = u0tmp / w0;
u1 = u1tmp / w1;
deltaTmp = (float)(w0 *w1* pow((u0 - u1), 2)) ;
if(deltaTmp > deltaMax)
{
deltaMax = deltaTmp;
threshold = i;
}
}

/***********************************************/

MatIterator_ grayit, grayend;
for(grayit = roi.begin(),grayend = roi.end(); grayit != grayend; ++grayit)
{
if(*grayit
{
*grayit = 0;
}
else
{
*grayit = 255;
}
//outfile }

bool data_flag = false;
int x = 0,y = 0;

for(int i=0;i {
uchar * p = roi.ptr(i);
for(int j=0;j {
y = -i+240;
x = j-320;

if(p[j]==0 && data_flag==false)
{
data_flag=true;
outfile outfile outfile

outfile }
else if(p[j]==0 && data_flag==true)
{

}
else if(p[j]==255 && data_flag==true)
{

data_flag=false;
x=x-1;
outfile outfile x=x+1;
outfile outfile }
//outfile /* outfile outfile outfile outfile outfile if(p[j]==255)
outfile else
outfile outfile }
data_flag=false;
}

outfile.close();
imwrite("converted.png",roi);
return 0;
}

在脚本开发完成以后,再编写自己的相应下位机接口控制程序,即可完成开发,实现自己精彩纷呈的Edison智慧应用。

文章来源:英特尔开发人员专区