안녕하세요. 충남대학교 컴퓨터공학과 김진섭입니다.
저는 지금 인스페이스에서 백마인턴쉽(4주)를 수행하고있는데, 벌써 3주의 끝에 오게되었네요. 아마, 이번 포스팅이 인스페이스 인턴 생활의 마지막? 포스팅이 될 것 같습니다.
이번시간에는 지난번에 사용하였던 OpenMV의 코드를 응용하여 바둑판에서 바둑돌의 위치를 주면 해당 위치에 바둑돌을 두는 코드를 소개하겠습니다.
우선 이전에 포스팅해둔 OpenMV를 기본적으로 모두 수행해보셨다는 가정하에 진행할 계획이니까, 한번 따라서 수행해 보시고 이번 포스팅을 읽어주시면 감사하겠습니다.
저는 메가보드의 아두이노 코드를 변경하여 바둑돌을 처리할 수 있도록 구현하였습니다. 따라서 코드설명은 OpenMV와 uArm의 부분을 제외한 아두이노 부분만 설명 드리도록하겠습니다.
바둑돌을 두는 원리 소개
바둑돌을 두기 위해서는 바둑돌을 찾아야하고, 해당 바둑돌을 원하는 바둑판 위치에 두어야합니다.
위 두 방법을 어떻게 수행하였는지 설명드리도록 하겠습니다.
사용할 바둑돌을 찾기
먼저 사용할 바둑돌을 찾는 원리를 소개드리겠습니다. 바둑돌을 찾는 방법으로 두가지를 설명드리겠습니다.
첫번째 방법은 고정된 위치에 바둑돌을 두고, 해당 좌표를 아두이노에 어떤 변수에 저장하여둔 뒤 나중에 시리얼 통신을 이용해 uArm을 이동시켜 찾는 방법입니다. 위 방법은 구현이 상당히 쉽지만, 조금이나마 환경이 바뀌게 된다면(uArm의 위치가 변경되거나 바둑돌이 변경되는 경우)
모두 다시 설정해 주어야 한다는 문제점이 있습니다.
두번째 방법은 OpenMV를 사용하여 바둑돌을 찾아서 두는 방법입니다. 이 방법은 매번 구현때마다 세팅을 수행하지 않다도 된다는 장점이있습니다. 하지만 단점은 구현이 상당히 까다롭고, OpenMV의 카메라 화질 문제, 그리고 가장 큰 문제로 바둑돌의 z좌표 계산이 어렵다는 문제점을 가지고있습니다.(uArm에서는 바둑돌을 잡았는지 확인하는 방법이 없습니다.)
저는 위 두가지 방법을 약간 섞어 사용하였으며, OpenMV관련 예제 코드를 활용하여 구현하였습니다. 우선, 바둑돌의 위치를 고정시킬만한 물품을 찾아야합니다.(저는 계란판을 사용하였습니다...) 그 뒤, 해당 계란판칸 중 한 칸에 빨간색 정사각형 물품을 놓은 뒤, 그 정사각형 물체를 기준으로 상절대적인 거리를 계산해 아두이노에 변수로 넣어두었습니다. 따라서 OpenMV를 이용해 빨간색 정사각형 물체를 찾으면, 해당 좌표를 계산하고, 그 좌표를 기준으로 사용하고자하는 공간을 index처럼 접근하여 돌을 빼내도록 만들었습니다.
원하는 바둑판 위치에 두기
원하는 바둑판 위치에 두는데는 많은 제약조건이 있습니다. 예를 들면, 로봇팔이 접근할 수 있는 팔의 길이와 같은 것 입니다. 로봇팔이 너무 판과 붙어있게되면, 로봇팔과 가까운 바둑판에 바둑돌을 두지 못하고, 너무 멀리 두게되면 바둑판에 접근을 못하게되는 문제점이있습니다.
따라서, 바둑판과 로봇팔의 적당한 거리를 찾는것이 중요합니다.
해당 거리를 찾으셨다면, 이제 바둑판에 바둑돌을 두어야하는데, 바둑판 자체를 비전으로 처리하여 두고자하는 곳을 찾는것은 굉장히 어려운 일입니다. 따라서, 바둑판에 원하는 위치에 돌을 두기 위해서는 각각 바둑판의 착수점마다 고정값을 저장해두고, 해당 바둑판의 좌표를 주면 해당 값으로 이동하여 바둑돌을 두어야합니다. 즉, 위에서 사용할 바둑돌을 찾을 때 첫번째 방법의 문제점이 그대로 나타나게되는 문제점이 발생합니다.
저는 환경이 바뀌면 모든 좌표값을 다시 계산해 다시 써 넣어주기 보다는 특정 값만 변경하면 모든 좌표가 계산되도록 하는 방법을 고민하였습니다.
(바둑판은 한칸의 크기는 모두 동일하다는 원리를 이용하였습니다.)
위 방법을 사용하면 바둑판의 전체좌표를 수정해줄 필요 없이 로봇팔이 바라보고있는 위치를 기준으로 우측 최 하단 부분의 착수점의 좌표만 수정하여주면됩니다.
코드 소개
우선 코드를 수행하기 위하여, 선언한 변수들을 소개드리도록 하겠습니다.
위 변수중 board_length와 omok_length 와firstX 그리고 firstY는 위 코드를 사용하실 때 반드시 변경해 주셔야합니다!
실행환경이 바뀔 때 마다 해당 변수들의 값을 변경해주시길 바랍니다.
메소드의 헤더정보도 보여드리겠습니다.
다음으로, 메소드를 하나씩 소개드리도록하겠습니다.
위 메소드는 uArm이 움직이기를 기다리는 메소드입니다. uArm에 아두이노가 시리얼 통신으로 움직이라는 명령을 내리고 나서, 바로 아래의 명령어를 실행하기 때문에, Race Condition과 비슷한 문제를 일으키게 됩니다. 따라서, 위 문제를 해결하기 위해서는 위 메소드가 필요합니다.
(ex uArm은 움직이고 있는데, 아두이노는 OpenMV에 물체를 찾으라고 명령하는 경우)
setup메소드 부분입니다. 원하는 작업을 처리하기 위하여, 여러가지 설정을 해주는 역할을 수행합니다.
바둑돌을 찾을 때, 빨간 물체로부터 떨어진 좌표의 offset을 설정하는 메소드입니다.
위 코드를 보면 총 7개의 바둑돌 집을 사용함을 확인할 수 있습니다.
위 메소드는 사용할 바둑돌을 가져오는 메소드입니다. Index를 OmokNum%7로 계산하여 넣어주는 이유는 OmokNum은 현재 오목돌을 둔 개수를 의미하며, 총 7개의 공간을 사용하기 때문에 나머지연산을 통해 사용할 바둑돌을 가져오는 것 입니다.
uArm에 명령할 명령을 만들고, 시리얼 통신을 이용해 움직이도록 하여줍니다.
('M2231 V1' 명령어를 주석처리한 이유는, 현재 테스트를 진행중이기 떄문이며, Suction Cup이 작동할 때 소음이 발생해서 이를 사용하지 않도록하기 위해 잠시 주석처리해 둔 것입니다.)
오목을 바둑판의 원하는 위치에 두는 메소드입니다. 우선, 오목을 두기위해 바둑돌을 가져오는 getStorn메소드를 실행해 줍니다.
바둑돌의 좌측상단부터 0,0으로 계산해주기 위해서, board_length(바둑판의 차수)에서 두고자 하는 바둑판의 x,y좌표를 뺀 뒤 바둑판의 길이에 대한 좌표 omok_length를 곱하여 사용하였습니다.
해당 좌표로 이동하는 명령을 uArm에 시리얼 통신으로 보내주고, 해당 좌표에 바둑돌을 두게됩니다.
loop는 테스틀를 위해서 위처럼 구현하였습니다.
*그 외 기타 메소드들은 모두 openMV를 실행하는 코드에서 약간 변형한 정도이기 때문에 추가 설명은 하지 않도록 하겠습니다.
실행 결과 동영상
위 결과는 Test의 일부만 확인하는 동영상입니다.
약 한달과정간 블로그 포스팅을 하며 제가 배운 내용을 공유하였는데, 매우 유익하고 좋은 경험이었던것 같습니다. 올해 4학년으로 학부 생활을 하며 계속 블로그를 할지는 모르겠으나, 상당히 저에게 많은 도움을 줬다고 생각합니다.
이상으로 포스팅을 마치도록하겠습니다. 감사합니다.
ps) OpenMV를 사용하지는 않지만, 절대경로를 적용하여 구현한 프로젝트를 github에 올려두었습니다. 참고하시길 바랍니다.
https://github.com/jin2609/uArm_Omok
'Etc > odds and ends' 카테고리의 다른 글
마크다운(Markdown) 문법 정리 (0) | 2021.07.15 |
---|---|
Git Blog에 이미지 업로드 Tip (1) | 2021.07.15 |
OpenMV가 바둑돌을 찾아내도록 코드를 구현해봅시다. (0) | 2019.01.04 |
uArmSwiftPro Open MV사용해보기 (2) | 2019.01.02 |
Python으로 uArm 제어하기 (4) | 2018.12.28 |