我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛
今天公司组织发福利,端午的福利,粽子、、、 也不是直接的发粽子。而是给你礼品卷,自己选择相应的礼品进行兑换。
就是这么个东西,由于我们公司一直致力于做工业智能化,我就查了一下粽子的生产流程: 我的个乖乖,从来没有关注过粽子的生产,今天以卡,基本上属于人工生产的方式,这怎么能忍。一个做智能制造的,怎么能忍受人工生产呢。所以,我就农了这篇文章,表达一下我的看法,当然了,实现全自动的可能性应该没有,应为预算太高,粽子一年就买几天,回本太慢了。
基本上都属于人工,那么我们就来对粽子生产的的某些功能进行升级吧!
粽子的分类以及抓取放到包装盒
由于我这里没有粽子的产线,智能放一个大体上相同的
我们通过前端的视觉拍照,得到粽子的大小以及在传送带上的位置,把他发送给机器人,机器人根据得到的数据在后方将粽子抓取到相应的包装盒。
前期标定
我们通过手眼标定的方式将机器人和相机标定到同一个坐标系下面,具体操作不走如下:
1.我们首先在视觉相机下方找到九个点,平且求出9个点在相机坐标下的像素坐标值P(i);
2.传送带万千移动,我们记录一下传送带往前走了的编码的脉冲量M;
3.将九个点的位置以机器人为坐标,记录下9个点的机器人坐标数据q(i);
我们通过机器人端的开发包建立随动坐标,将我们的数据传入到随动坐标中;
视觉这块,我们将的到的机械的坐标和视觉的坐标合二为一,通过halcon9点标定的方式来进行一个标定;
```js
*图像坐标 areacenter(SortedRegions,Area,Row,Column) % Columnrobot := [275,225,170,280,230,180,295,240,190]
*机器人9点的列坐标 Rowrobot := [55,50,45,5,0,-5,-50,-50,-50] *机器人9点的行坐标 vectortohommat2d(Row,Column,Rowrobot,Columnrobot,HomMat2D) *求解变换矩阵,HomMat2D是图像坐标和机械手坐标之间的关系 ```
`affinetranspoint_2d(HomMat2D,Row2,Column2,Qx,Qy)'
'*由像素坐标和标定方式求出机器人基础坐标系中的坐标 `
视觉程序
我们首先以粽子的原图作为模型,通过模型识别定位
示例如下:
```js
- This example program uses shape-based matching to align ROIs for the measure
- tool, which then inspects individual razor blades.
- The program can be run in two modes: (1) with the full affine transformation
- (2) using translate_measure
- Modify the next line to switch between the modes. USINGTRANSLATEMEASURE := 0
- general configuration of HDevelop devupdatewindow ('off')
- image acquisition and window size readimage (ModelImage, 'razors1') getimagepointer1 (ModelImage, Pointer, Type, Width, Height) devclosewindow () devopenwindow (0, 0, Width, Height, 'white', WindowHandle) devsetpart (0, 0, Height - 1, Width - 1) devdisplay (ModelImage)
- colors and other settings for the visualization devsetcolor ('cyan') devsetdraw ('margin') devsetline_width (2) stop ()
- ------------------- start of the application ----------------
- -> select the model object Row1 := 46 Column1 := 57 Row2 := 79 Column2 := 94 genrectangle1 (ROIPart1, Row1, Column1, Row2, Column2) genrectangle1 (ROIPart2, Row1 + 364, Column1 + 13, Row2 + 364, Column2 + 13) union2 (ROIPart1, ROIPart2, ModelROI) areacenter (ModelROI, Area, CenterROIRow, CenterROIColumn) devdisplay (ModelImage) dev_display (ModelROI) stop ()
- -> create the model reducedomain (ModelImage, ModelROI, ImageROI) createshapemodel (ImageROI, 4, 0, 0, 'auto', 'none', 'usepolarity', 30, 10, ModelID) inspectshapemodel (ImageROI, ShapeModelImage, ShapeModelRegion, 1, 30) getshapemodelcontours (ShapeModel, ModelID, 1) devclearwindow () devsetcolor ('blue') devdisplay (ShapeModelRegion) stop ()
- step 1: create variables describing the measurement ROIs and display them Rect1Row := 244 Rect1Col := 73 DistColRect1Rect2 := 17 Rect2Row := Rect1Row Rect2Col := Rect1Col + DistColRect1Rect2 RectPhi := rad(90) RectLength1 := 122 RectLength2 := 2 genrectangle2 (MeasureROI1, Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2) genrectangle2 (MeasureROI2, Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2) devdisplay (ModelImage) devsetcolor ('yellow') devdisplay (MeasureROI1) dev_display (MeasureROI2)
- translate measurement ROIs to lie on XLD model (without clipping!) getsystem ('clipregion', OriginalClipRegion) setsystem ('clipregion', 'false') moveregion (MeasureROI1, MeasureROI1Ref, -CenterROIRow, -CenterROIColumn) moveregion (MeasureROI2, MeasureROI2Ref, -CenterROIRow, -CenterROIColumn) setsystem ('clipregion', OriginalClipRegion) DistRect1CenterRow := Rect1Row - CenterROIRow DistRect1CenterCol := Rect1Col - CenterROIColumn DistRect2CenterRow := Rect2Row - CenterROIRow DistRect2CenterCol := Rect2Col - CenterROIColumn if (USINGTRANSLATEMEASURE != 0)
- -> measure objects are created only once in advance and then translated later genmeasurerectangle2 (Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1) genmeasurerectangle2 (Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2) endif stop ()
- step 2: find the objects in another image readimage (SearchImage, 'razors2') devdisplay (SearchImage) findshapemodel (SearchImage, ModelID, 0, 0, 0.8, 0, 0.5, 'leastsquares', 0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score) if (|Score| > 0) for i := 0 to |Score| - 1 by 1 * step 3: determine the affine transformation vectorangletorigid (0, 0, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject) affinetranscontourxld (ShapeModel, ModelAtNewPosition, MovementOfObject) devdisplay (ModelAtNewPosition) * step 4: measure width and distance of the teeth * -> display the moved ROIs affinetransregion (MeasureROI1Ref, MeasureROI1AtNewPosition, MovementOfObject, 'constant') affinetransregion (MeasureROI2Ref, MeasureROI2AtNewPosition, MovementOfObject, 'constant') devdisplay (MeasureROI1AtNewPosition) devdisplay (MeasureROI2AtNewPosition) affinetranspixel (MovementOfObject, DistRect1CenterRow, DistRect1CenterCol, Rect1RowCheck, Rect1ColCheck) affinetranspixel (MovementOfObject, DistRect2CenterRow, DistRect2CenterCol, Rect2RowCheck, Rect2ColCheck) if (USINGTRANSLATEMEASURE != 0) * -> translate the already created measure objects translatemeasure (MeasureHandle1, Rect1RowCheck, Rect1ColCheck) translatemeasure (MeasureHandle2, Rect2RowCheck, Rect2ColCheck) measurepairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1) measurepairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all', RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2) else * -> create new measure objects and destroy them after the measurement RectPhiCheck := RectPhi + AngleCheck[i] genmeasurerectangle2 (Rect1RowCheck, Rect1ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1) genmeasurerectangle2 (Rect2RowCheck, Rect2ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2) * step 5: perform the measurement measurepairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1) measurepairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all', RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2) closemeasure (MeasureHandle1) closemeasure (MeasureHandle2) endif * step 6: check for too short or missing teeth NumberTeeth1 := |Width1| NumberTeeth2 := |Width2| devsetcolor ('red') if (NumberTeeth1 < 37) for j := 0 to NumberTeeth1 - 2 by 1 if (Distance1[j] > 4.0) RowFault := round(0.5 * (RowEdge11[j + 1] + RowEdge21[j])) ColFault := round(0.5 * (ColEdge11[j + 1] + ColEdge21[j])) disprectangle2 (WindowHandle, RowFault, ColFault, 0, 4, 4) devopenwindow (0, Width + 20, 80, 80, 'black', WindowHandleZoom) devsetpart (RowFault - 10, ColFault - 10, RowFault + 10, ColFault + 10) devdisplay (SearchImage) disprectangle2 (WindowHandleZoom, RowFault, ColFault, 0, 4, 4) stop () devclosewindow () devsetpart (0, 0, Height - 1, Width - 1) endif endfor endif if (NumberTeeth2 < 37) for j := 0 to NumberTeeth2 - 2 by 1 if (Distance2[j] > 4.0) RowFault := round(0.5 * (RowEdge12[j + 1] + RowEdge22[j])) ColFault := round(0.5 * (ColEdge12[j + 1] + ColEdge22[j])) disprectangle2 (WindowHandle, RowFault, ColFault, 0, 4, 4) devopenwindow (0, Width + 20, 80, 80, 'black', WindowHandleZoom) devsetpart (RowFault - 10, ColFault - 10, RowFault + 10, ColFault + 10) devdisplay (SearchImage) disprectangle2 (WindowHandleZoom, RowFault, ColFault, 0, 4, 4) stop () devclosewindow () devsetpart (0, 0, Height - 1, Width - 1) endif endfor endif devsetcolor ('yellow') stop () endfor endif
- ------------------- end of the application -----------------
- clean up if (USINGTRANSLATEMEASURE != 0) closemeasure (MeasureHandle1) closemeasure (MeasureHandle2) endif devupdatewindow ('on') clearshapemodel (ModelID) ```
机器人配合
在我们做完酒店标定以后,机器人只需要将视觉传过来的坐标带入到随动坐标系中,这样就能够得到准确的随动坐标。
结束语
本次我们提升了包装的速率,后续我们将对整个产线都实行自动化的功能升级;