前言
最近在搞机械臂的研究,其中涉及到的一个问题就是对于坐标系的确定;
现在使用的方案就是将机械臂放在下面,摄像头通过支架架在机械臂正上方40cm左右的位置,此时需要机械臂确定好坐标位置,通过原点坐标进而求出每一个舵机该转动的角度。
随着每一次系统的移动,坐标原点的位置可能会发生偏差,因此需要设计一种方案来确定坐标原点的位置,本次的设计方案为:
操作机械臂在平面上画一个同心圆。然后在同心圆内找到任意三个点(尽量分散一点,有利于减少误差)。
提示:以下是本篇文章正文内容,下面案例可供参考
一、操控机械臂画圆
这个步骤很简单的,可以让机械臂先摆正。然后动手画一个圆弧。或者是下位机控制机械臂握住马克笔,然后转半圈。
二、获取关键点坐标
当我们找到这三个点以后,此时可以控制摄像头进行识别。我的方案是通过写一个色块识别的程序,然后讲物块放在上面画的同心圆的三个任一点上面,此时,可以动手记录下来三个点的坐标。
色块识别代码(示例):
void imgThread::startVideo()
{
int i;
int x,y;
Mat Gray; //灰度图
Mat Otus; //黑白图
Mat Hsls; //hsl格式图片
Mat Frame; //原图
Mat dstImg;
Mat dstImg2;
// int h_min=156;//红色
// int s_min=97;
// int v_min=159;
// int h_max=180;
// int s_max=255;
// int v_max=255;
int h_min=100;//蓝色
int s_min=76;
int v_min=76;
int h_max=124;
int s_max=255;
int v_max=255;
// int h_min=26;//黄色
// int s_min=160;
// int v_min=155;
// int h_max=34;
// int s_max=255;
// int v_max=255;
VideoCapture capture(1 ); //读取外部摄像头
capture.set(CAP_PROP_FPS, 120);//帧率 帧/秒
//stopped = false;
qDebug()<<"Frame.cols:"<<Frame.cols;//打印列位置
qDebug()<<"Frame.rows:"<<Frame.rows;//打印行位置
while(1)
{
if(!stopped)
{
capture >> Frame;//将视频帧读取到Mat矩阵
dstImg = Frame(Range(20, 380), Range(135, 540));//裁剪
Mat textimg=dstImg.clone();
cv::cvtColor(dstImg,dstImg,COLOR_BGR2HSV);
Scalar hsv_min(h_min,s_min,v_min);
Scalar hsv_max(h_max,s_max,v_max);
Mat dstimg=Mat::zeros(dstImg.size(),CV_8U);
inRange(dstImg,hsv_min,hsv_max,dstimg);
Mat element=getStructuringElement(MORPH_RECT,Size(5,5));
morphologyEx(dstimg,dstimg,MORPH_DILATE,element,Point(-1,-1),4);
Otus=dstimg.clone();
getxy(Otus,x,y); //寻找色块位置
if(x!=-1||y!=-1) //有位置才发
{
cv::circle(Otus,center, 10, Scalar(120, 120, 120), -1);
emit sendxy(x,y);//发送位置信息
}
else
{
emit sendxy(-2,-2); //没找到位置。
}
emit inDisplay(
QPixmap::fromImage(
QImage(
dstImg.data,
dstImg.cols,
dstImg.rows,
dstImg.step,
QImage::Format_RGB888)
.rgbSwapped()));
//qDebug()<<"i="<<i++;
emit outDisplay(
QPixmap::fromImage(
QImage(
Otus.data,
Otus.cols,
Otus.rows,
Otus.step,//访问图片像素
QImage::Format_Grayscale8)
.rgbSwapped()));
}
}
}
上面的那个是色块识别的核心代码,可以通过这个来找到物块的位置。
三、获取圆心
获取圆心的计算可以找这个大佬
文章链接
然后就是代码部分了;
作为一个刚入门的程序小白,自己就动手写了一个简单的程序来得到圆心的坐标以及半径。

将需要的内容放里面。
接下来对大家做一个介绍
寻找圆心算法:
QPointF Widget::tcircle(QPointF pt1, QPointF pt2, QPointF pt3, double &radius)
{
double x1 = pt1.x(), x2 = pt2.x(), x3 = pt3.x();
double y1 = pt1.y(), y2 = pt2.y(), y3 = pt3.y();
double a = x1 - x2;
double b = y1 - y2;
double c = x1 - x3;
double d = y1 - y3;
double e = ((x1 * x1 - x2 * x2) + (y1 * y1 - y2 * y2)) / 2.0;
double f = ((x1 * x1 - x3 * x3) + (y1 * y1 - y3 * y3)) / 2.0;
double det = b * c - a * d;
if( fabs(det) < 1e-5)
{
radius = -1;
return QPointF(0,0);
}
double x0 = -(d * e - b * f) / det;
double y0 = -(a * f - c * e) / det;
radius = hypot(x1 - x0, y1 - y0);
return QPointF(x0, y0);
}
计算并显示:
void Widget::on_button_0_clicked()
{
pf0.setX(ui->Spinbox0->value());
pf0.setY(ui->Spinbox1->value());
pf1.setX(ui->Spinbox2->value());
pf1.setY(ui->Spinbox3->value());
pf2.setX(ui->Spinbox4->value());
pf2.setY(ui->Spinbox5->value());
pf3 = tcircle(pf0,pf1,pf2,radius);
QString pointx = QString("中心(%1,%2) 半径%3").arg(pf3.x()).arg(pf3.y()).arg(radius);
ui->lineEdit_4->setText(pointx);
cout<<pf3.x()<<endl;
cout<<pf3.y()<<endl;
cout<<radius<<endl;
}
清除信息:
void Widget::on_button_1_clicked()
{
pf0.setX(0); //清除原来的信息
pf0.setY(0);
pf1.setX(0);
pf1.setY(0);
pf2.setX(0);
pf2.setY(0);
ui->Spinbox0->setValue(pf0.x());
ui->Spinbox1->setValue(pf0.y());
ui->Spinbox2->setValue(pf1.x());
ui->Spinbox3->setValue(pf1.y());
ui->Spinbox4->setValue(pf2.x());
ui->Spinbox5->setValue(pf2.y());
QString pointx = QString("请重新输入:");
ui->lineEdit_4->setText(pointx);
}
下面是测试的图片:

点击清除以后:

总结
经过了两个小时的编写,才完成了这个小的项目,也算是对自己的能力的一个测试吧。本来感觉十几分钟就可以搞定了,结果遇到的最麻烦的事情却是语法的错误。
QString pointx = QString(“中心(%1,%2) 半径%3”).arg(pf3.x()).arg(pf3.y()).arg(radius);`
就是这部分,因为QT里面不能使用sprintf进行字符串的连接,只能使用这种方法讲字符拼起来放到文本框进行显示。
希望给需要的朋友带来一点点帮助。

656

被折叠的 条评论
为什么被折叠?



