메이커 Maker

메타버스(Metaverse) 경험 기반 원격 제어 로봇 follow bot

지구빵집 2022. 3. 28. 09:32
반응형

 

 

다시 한 학기 마지막 행사를 치렀다. 아이들은 이미 내린 선택이나 결정을 자신에게 아주 좋게 만들 줄 아는 아이들이다. 조금도 주저하지 않고 '자기 것'이라고 말할 줄 안다. 젊은 아이들은 누구나 그렇듯 자기감정을 소중하게 여기고 표현을 잘한다. 일상에서 풍기는 태도나 자세도 아름답다. 아이들이 작업한 리스트를 남기고 내용을 간단하게 정리하고 블로그와 유튜브 계정을 연결하기로 한다. 늘 잘하려고 애쓰는 선생님이 안쓰러운지 아이들은 어떤 요청도 소홀히 하지 않는다. 

 

웬만하면 아이들 문서를 수정하지 않는다. 그대로 두는 것도 교육이고 무엇을 더 해야 하는지 아는 것도 교육이다. 그대로 아무것도 하지 않는 것도 도움이 된다. 우린 항상 무엇인가를 하려고 주위에 관심을 쏟고 집중을 흩트리는데 그러지 않아도 된다. 

 

유튜브 영상을 보시려면 링크를 클릭

 

Follow Bot: 메타버스(Metaverse) 경험 기반 원격 제어 로봇

놀아주 개 - 반려동물 공놀이 기구

반려견 무선 목줄

칵테일 제조 서비스 로봇

지하철 임산부 좌석보호 시스템

음식을 직접 테이블로 배달하는 비대면 서비스로봇

시각 장애인 횡단보도 안전 지킴이 

 

 

2021년 1학기 어드벤처 디자인 작품 목록 리스트와 블로그 링크

 

Follow Bot: 메타버스(Metaverse) 경험 기반 원격 제어 로봇

놀아주 개 - 반려동물 공놀이 기구

반려견 무선 목줄

칵테일 제조 서비스 로봇

지하철 임산부 좌석보호 시스템

음식을 직접 테이블로 배달하는 비대면 서비스로봇 

시각 장애인 횡단보도 안전 지킴이

 

 

메타버스(Metaverse) 경험 기반 원격 제어 로봇 follow bot 

밤 사이에 눈이 조금 내렸다. 바람에 한 곳으로 몰린 곳도 있고, 녹은 자리도 있다. 정원에 잠깐 나갔다가 들어올 때 눈이 없는 곳으로만 돌아온다. 눈이 신발에 묻으면 연구실에 들어와 녹아서 바닥이 더러워지기 때문이다. 더는 미룰 수 없어서 시작한 아이들 작품 활동을 기록하고 있다. 요번 주는 문서번호: 6772-6778까지 작성하기로 한다.

 

 

메타버스(Metaverse) 경험 기반 원격 제어 로봇 follow bot 

 

follow bot 개요 

 

코로나 사태가 2년에 가깝게 장기적으로 유지가 되어가는 만큼 사람들은 점점 집 바깥으로 나가는 일이 줄어들게 되었고, 그로 인해 기본적인 욕구 중 하나인 인간의 사회성, 사람들을 만나는, 외로움을 느끼고 싶지 않고 싶은 욕구의 충족이 제대로 되지 않고 있습니다. 그러한 상황의 개선을 위해서 생각한 것이 바로 팔로우 봇을 통해 나갈 수 없는 상황에서 서로 보고 싶은 사람들을 실제 만난 것과 같은 경험을 할 수 있고 이를 통해서 사람들의 부족해진 만남을 지속적으로 이어나갈 수 있도록 도와줄 수 있습니다. 

 

구성품 설명

 

모터는 전력 에너지를 동력 에너지로 변환하는 전동기입니다. 모터는 고정자가 회전자에 자기력을 가하고, 자기력의 밀거나 당기는 힘을 회전자가 받아 회전해서 에너지를 출력합니다. 모터의 수전 방식에 따라 DC 모터, AC모터로 분류할 수 있으며, 모터의 작동 방식에 따라 일반 모터, 스텝 모터, 서보모터로 분류할 수 됩니다. 

 

AC모터

 

AC모터는 교류를 전원으로 움직이는 모터입니다. 내부에 있는 고정자에 코일을 감싸 코일의 전자기 유도로 자기장이 변화합니다. 이때 회전자에서 회전하고 있는 자기장의 영향으로 유도전류가 생기고 회전을 하게 됩니다. AC모터는 수명이 길고 구동이 쉬우며 토크가 부드럽다는 장점도 있지만, 발열이 심하고 효율이 떨어지며 전자제어의 난이도가 높다는 단점 또한 가지고 있습니다. 

 

DC 모터

 

DC 모터는 고정자로 영구자석을 사용하고, 회전자(전기자)로 코일을 사용하여 구성한 것으로, 전기자에 흐르는 전류의 방향을 전환함으로써 자력의 반발, 흡인력으로 회전력을 생성시키는 모터입니다. 내부에 영구적인 고정자와 그보다 안에 있는 코일로 구성이 되어있습니다. 코일에 전류를 주어 자력을 만든 뒤 영구자석의 인력과 척력으로 회전을 시키는 방식입니다. 이러한 DC 모터는 기동 토크가 크고 출력효율이 높으며 가격이 저렴하다는 장점이 있지만, 정류자와 브러시가 있기 때문에 내구성이 약하다는 단점을 가지고 있습니다. DC 모터의 종류와 설명입니다.

 

1) 스테핑 모터

 

스테핑 모터(Stepping Motor)는 일명 스텝 모터, 펄스 모터, 스테퍼 모터 등이라고 불려지고 있는데 이것을 번역하면 보진 전동기 또는 계동 전동기라고 할 수 있다.

 

보진은 한 발 한 발 단계적으로 움직이는 것을 말하고 스테핑 모터의 동작 이미지를 잘 표현하고 있다. 그런데 스테핑 모터의 최대 특징은 펄스 전력에 대응하여 회전한다는 것이다. 게다가 입력 펄스수에 비례하여 회전각이 변위되고 또 입력 주파수에 비례하여 회전 속도가 변화하기 때문에 피드백함이 없이 모터의 동작을 제어할 수 있다. 이러한 이점을 가진 스테핑 모터는 피드백계가 없는 위치 결정 제어의 구동원으로 FA, OA 관계를 비롯해서 폭넓게 사용되고 있다. 위치 결정 제어를 다른 모터에서 실현하려면 피드백 제어가 필요하게 된다. 스테핑 모터를 분류하는 경우 자기회로, 즉 모터의 구조에 의한 분류법이 일반적이다.

 

이것에는 로터부를 영구 자석으로 만든 PM형(Permanent Magnet Type), 로터부를 기어 모양의 철심으로 만든 VR형(Variable Reluctance Type), 그리고 로터부를 기어 모양의 철심과 자석으로 구성한 HB형(Hybrid Type)이 있다. PM형은 로터부에 다극착자된 영구 자석을 사용하고 그 둘레에 구동 계자(스테이터)를 설치한 것이다. 이 PM형은 판금 모양의 요크에 발톱을 세운, 크로 폴(craw pole)형이 많이 보급되어 있다. VR형은 로터부에 고투자율 재료를 사용한 기어 모양 회전체를 사용하고 이것과 스테이터 코일에서 발생하는 회전력을 이용한 것이다. HB형은 PM형과 VR형의 장점을 잘 짜 맞춘 것인데 스테핑 모터 중에서 가장 우수한 회전 특성을 나타낸다.

 

또 스테핑 모터의 분류 방법으로는 회전형, 직진형 등의 운동 형태에 의한 분류, 원통형, 박형 등의 외형에 의한 분류, 2상, 3상, 5상 등의 구동 권선에 의한 분류, 1상 여자, 2상 여자, 1-2상 여자 등의 여자 모드에 의한 분류법도 있다.

 

2) Brushless DC Motor (BLDC)

 

브러시리스 모터(Brushless Motor)는 DC 모터에서 브러시와 정류자(Commutator)를 없애고 전자적인 정류 기구를 설치한 모터이다. 따라서 기계적인 노이즈뿐만 아니라 전기적인 노이즈도 발생되지 않는다.

 

브러시리스 모터의 장점은 특히 원리적으로 노이즈가 발생하지 않는 것이다. 기타 초저속 또는 초고속, 다극(자석의 수가 많다.)긴 수명의 모터가 간단히 만들어지는 점도 장점이라고 할 수 있다. 그런데 브러시리스 모터의 구조는 중심에 회전하는 마그넷이 있고 그 둘레에 구동 코일이 설치되어 있다.

 

브러시리스 모터의 작동원리는 DC 모터와 같이 플레밍의 왼손 법칙이며 코일 또는 영구 자석의 어느 쪽이 회전해도 그 작동 원리는 같다. 단, 브러시리스 모터에는 정류자가 없기 때문에 이것에 대신하는 전자 정류 회로가 필요하게 된다.

 

이 회로는 홀 소자 등의 자극 센서를 사용하여 마그넷 로터가 어느 위치에 있는가를 검지하고, 이 신호를 기초로 전자 회로를 제어하여 회전 자기장을 발생시킨다. 이것이 브러시리스 모터의 구동회로인데 매우 회로 구성이 복잡하게 되기 때문에 보통은 전용 IC가 사용되고 있다. 브러시리스 모터의 주요한 용도는 VTR의 실린더, 카세트 데크의 캡스턴, FDD, CD 플레이어 등이며 높은 회전 성능, 긴 수명이 요구되는 모터로 사용되고 있다. 본래부터 브러시나 정류자를 필요로 하지 않는 AC 모터는 브러시리스 모터로 분류되지 않는다.

 

3) 인덕션 모터

 

인덕션 모터(Induction Motor)는 AC 모터의 일종이며 회전 자계형으로 분류되어 있는 모터이다. 이 모터의 작동 원리는 고정자 권선에 흐르는 교번(교류)전류에 의해 발생하는 회전 자기장과 로터부에 발생하는 유도 전류와의 상호작용에 의해 생기는 회전력이다.

 

이 때문에 인덕션 모터를 유도모터라고 부르는 경우도 있다. 그 내부 구조는 로터부(회전자)는 규소 강판을 적층한 것, 슬롯부는 구리나 알루미늄 등으로 농형으로 권선을 형성한 것이 사용되고 있다. 또 이 종류의 인덕션 모터의 토크 발생부는 로터나 스테이터(고정자)의 권선부가 아니고 그 대부분이 철심에 집중되어 있다. 그리고 인덕션 모터는 부하(토크)에 대응한 회전수로 회전하는데 이것에는 어느 정도의 정속성이 있다. 따라서 그다지 엄밀한 정속성이 요구되지 않는 동력용 모터로서 널리 사용되고 있다. 인덕션 모터에도 여러 가지 종류가 있으며 소형의 것으로는 단상 콘덴서 구동형이 가장 많이 보급되어 있다. 특성적으로는 입력 전압이 AC 100V, 200V(50/60Hz), 출력 파워가 수 W 이상, 폴수(자극수)는 2극과 4극이 일반적이다. 또 그 회전수 N[RPM]은 다음 식으로 구할 수 있다. 식 중의 f는 전원 주파수, P는 폴수, S는 미끄럼을 나타낸다(S는 동기 속도[전원 주파수에 의존한다]와 회전 속도의 차를 나타내고 회전 속도는 동기 속도보다 조금 낮게 된다.)

 

4) 리버시블 모터

 

리버시블(Reversible Motor)는 인덕션 모터의 일종이며 우회전, 좌회전 어느 방향으로도 같은 특성이 얻어지는 모터이다. 원리적으로도 인덕션 모터와 같으나 빈번한 정역전에 견디고 큰 시동 토크를 얻기 위해 일반 인덕션 모터와 같이 주코일, 보조 코일의 관계는 없다. 주요한 용도는 세탁기의 소용돌이 발생용 모터, 각종 자동 기기의 구동원 등이다. 리버시블(가역) 모터의 특징을 정리하면 다음과 같다. ① 빈번한 정역전에 적합하다. ② 시동 특성이 우수하다. ③ 단시간이면 크기에 비해 큰 출력이 얻어진다.

 

5) 셰이드형 모터

 

셰이드형 모터(Shaded Pole Motor)는 단상 교류 모터의 일종이며 1차 코일과는 별도로 1-2회전의 단락 코일(셰이딩 코일)을 감고 이것에 의해 회전 자기장을 발생시키는 모터이다. 일반적으로 AC 모터를 회전시키기 위해서는 2상 이상의 교류를 필요로 하는데 일반 가정용에는 단상 교류밖에 공급되지 않는다. 그 때문에 AC 모터를 움직이기 위해서는 어떤 대책이 필요하게 된다. 예를 들면 콘덴서를 사용하여 위상이 다른 별도의 전원을 만드는 방법도 있다. 셰이드형 모터에서는 콘덴서 대신에 몇 회전의 단락 코일을 감고 이것에 의해 3.14 / 2 이상 위상이 지연된 교류를 만들어 내고 있다. 즉 보통 공급되고 있는 단상 교류와 셰이딩 코일에 의해 만들어 낸 단상 교류를 조합하여 간단한 2상 교류를 실현하고 있다. 세이드형 모터의 특징은 구조가 간단하고 저가격이라는 점인데 수십 W가 한계이고 출력 효율이 낮다고 하는 결점도 있다. 주요한 용도는 소형의 선풍기나 엄밀한 회전특성(회전 변동, 토크 변동)을 필요로 하지 않는 장치 등이다. 셰이딩 코일은 인덕션 모터나 다음 항에서 설명하는 싱크로너스 모터에도 사용할 수 있으며 현재는 수 W의 인덕션 모터에도 많이 사용되고 있다. 또 세이드형 모터는 그 외관에 의해 스켈린턴 모터(skeletom Motor)라고도 불려지고 있다.

 

6) 싱크로너스 모터

 

싱크로너스 모터(Synchronous Motor)는 교류 모터의 일종이며 전원 주파수에 동기하여 회전하는 모터이다. 이 모터는 전원 주파수와 동기되었을 때 비로소 안정된 회전 특성이 얻어진다는 특징이 있다. 그 때문에 싱크로너스(동기) 모터라는 명칭으로 불려지고 있다. 이 모터는 로터가 동기 속도로 되지 않으면 토크의 발생 방향이 정해지지 않고 진동 등을 수반하여 정지된다. 또 모터에 최대 토크 이상의 부하를 가하면 동기 속도를 유지할 수 없게 되어 로터가 정지된다. 일반적으로 이 현상을 동기이탈, 또는 탈조라고 부르고 있다. 또 동기 이탈에 대하여는 앞에서 설명한 스테핑 모터에도 같은 현상이 나타난다. 싱크로너스 모터의 회전수 n[RPM] 은 위의 식으로 구할 수 있다. 여기서 f[Hz]는 전원 주파수, P는 폴수(자극수)이다. 예를 들면 2폴의 싱크로너스 모터를 50 Hz로 회전시키는 경우 그 회전수는 위의 계산식에 각각의 수치를 대입하면 120*50/2, 즉 3000회전으로 회전하게 된다. 그리고 이것이 60Hz이면 120*60/2이며 3600회전이 된다. 이와같이 전원 주파수를 안정시키면 모터의 회전수도 안정되기 때문에 시계나 타임스위치 등에 많이 사용되고 있다. 또 싱크로너스 모터에는 영구 자석형, 히스테리시스형, 인덕터형 등이 있으며 용도에 따라 각각 적합 것이 사용되고 있다.

 

7) 유니버설 모터

 

유니버설 모터(Universal Motor)는 직류나 교류로 회전시킬 수 있는 정류자 모터를 말한다. 유니버설이라는 말은 [여거가지 목적에 사용되는 만능]이라는 뜻이며 이 모터를 직류나 교류로 사용할 수 있기 때문에 이 명칭으로 불려지고 있다. 이 모터의 구조는 앞에서 설명한 직류 직권모터와 같으며 스테이터 코일과 로터 코일에 동일 전류를 흐르게 하며 회전력을 발생시킨다. 따라서 직류나 교류에서 토크의 발생 방향이 일정하게 되어 항상 일정한 방향으로 회전할 수 있게 된다. 또 유니버설 모터는 입력 단자에 공급하는 전압의 극성을 바꾸어도 회전 방향은 변하지 않는다. 유니버설 모터를 교류 전원으로 사용하는 경우 전원 주파수의 2배로 맥동하는데 50/60Hz 정도의 주파수이면 그 맥동은 별로 문제가 되지 않는다. 특징은 시동 토크가 크고 고속 회전이 쉽게 얻어진다는 것이다. 그 때문에 전차 등의 구동 모터로 많이 사용되고 있다. 한편, 결점으로는 브러시와 정류자가 있기 때문에 전기 노이즈, 기계 노이즈가 크고 수명도 그다지 길지 않다는 점 등을 들 수 있다.

 

8) 리니어 모터

 

Linear Motor 란 Direct로 직선 운동을 하는 모터의 총칭이다. 우리 주변에서 사용되고 있는 모터의 대부분은 회전식인데 각종의 가전제품이나 정보 기기에는 여러 곳에서 직선 운동형 모터가 사용되고 있다. 예를 들면 HDD, FDD의 헤드 이송 장치, 프린터, 재봉틀, 편직기, 자동 도어 컨베이어 등에는 리니어 모터가 사용되고 있다. 그런데 단순히 직선 운동만 시키는 것이면 회전형 모터에 볼나사를 병용하면 된다. 그러나 그 동작의 정밀도, 속도 등의 대한 요구가 높아지면 회전용 모터로는 대응할 수 없게 된다. 그래서 등장한 것이 리니어 모터이다. 이모터는 다이렉트로 직선 운동을 하기 때문에 정밀도와 속도가 상당히 높아진다. 리니어 모터의 종류로는 직류 교류에 한정하지 않고 대체로 어떤 모터로도 리니어 모터로 될 수 있다. 단, 그 성능, 경제성을 고려하면 그 종류도 자연히 한정된다. 예를 들면 직류이면 스테핑 모터나 브러시리스 모터, 교류이면 싱크로너스 모터, 인덕션 모터 등이 사용되고 있다. 리니어 모터의 장점은 앞에서도 설명한 바와 같이 다이렉트인 직선 운동이나 고속 작동이 가능한 것 외에 백래시가 없고 수명이 긴 것이다. 한편 단점으로는 일반적으로 고가라는 것이다.

 

9) 초음파 모터

 

초음파 모터는 자석이나 권선을 필요로 하지 않느 새로운 형의 구동원이다. 작동원리는 복수의 압전 세라믹을 사용하고 이것에 고주파 전압을 가하여 압전 세라믹을 진동시킨다. 그리고 이 진동력에서 탄성체, 마찰판을 거쳐 일정 방향의 구동력(회전력)을 얻는 것이다. 또 그 구동력은 회전형 외에 직진형(리니어 구동형)도 있다. 앞에서 초음파 모터는 새로운 형의 구동원이라고 하였는데, 종래 모터라고 하면 자석이나 권선을 사용하는 전자기의 모터를 지칭하였다. 그런데 이 초음파 모터는 20kHz 이상의 초음파 영역을 사용하는 전기력 모터인 것이다. 초음파 모터의 용도는 저속 회전에서 큰 힘을 필요로 하는 다이렉트 드라이브용 또, 현장 여건상 자기 에너지를 쓸 수 없는 장치의 구동원, 또는 초소형 사이즈의 구동원, 버니어 구동(미크론 단위의 미소 구동원) 등에 이용되고 있다. 초음파 모터에는 정재파 방식과 진행파 방식이 있으며 일반적으로는 후자의 진행파 방식이 이용되고 있다. 진행파 방식이란 압전 세라믹스를 금속의 탄성체에 맞붙인 스테이터와 로터부를 마주 접촉시켜 탄성체에 발생하는 종파와 횡파에 의한 진행파에서 구동력을 얻는 방법이다. 또 초음파 모터는 그 진동 주파수에 20kHz 이상의 초음파를 사용하고 있으며 이것은 모터 내부에서 그 대부분 이 회전력으로 변환되기 때문에 인간이나 기타 생물에게 위해를 주지 않는다.

 

10) 슬롯형과 슬롯리스 모터

 

모터의 전기자에는 얼마간의 권선을 필요로 하며 철판을 겹친 철심에 슬롯(홈)을 부착하고 여기에 코일을 감아 넣은 형식의 모터를 슬롯형 모터 (Slotted type Moter)라고 한다. 이 모터는 구동용 코일을 직접 슬롯 안에 감아 넣기 때문에 보빈은 필요 없고 구조는 매우 단단하게 된다. 그러나 돌극구조이기 때문에 코깅이 발생하고 이것이 토크 변동, 회전 변동 특성에 나쁜 영향을 주게 되는 단점도 있다. 한 편 슬롯이 없는 노터 이른바 슬롯리스 모터(Slotless Motor)는 철심 등에 슬롯이 없고 코일도 본딩 와이어(자기 융착선)를 사용하여 자립 형성하고 있다. 또 슬롯리스 모터는 어떤 위치에 있어도 균일한 자기 흡인력을 받기 때문에 코깅 현상이 없다.

 

11) 기어드 모터

 

기어드 모터(Geared Motor)는 모터의 회전축에 기어 등의 감속 기구를 부착한 것이며 이것에 의해 모터 단체로는 얻을 수 없는 저속 회전이 실현되거나 큰 토크를 발생시킬 수 있다. 또 기어(감속 기구)는 어떤 모터에도 부착할 수 있으므로, 어떤 모터라도 기어드 모터가 될 수 있다. 그런데 모터는 고속 회전시킬수록 효율이 좋고 경제성도 높아진다. 그 때문에 필요로 하는 회전수의 수십배, 수백 배로 모터를 회전시키고 여기에 기어를 짜 맞추어 감속하며 최종적으로 목적으로 하는 회전수를 꺼내고 있다(발전기 등은 기어로 증속할 수도 있다). 기어가 부착된 모터의 경우 기어에 의한 감속에 대응하여 그 토크도 증대되므로 비교적 소형의 모터에서도 쉽게 큰 토크를 얻을 수 있다. 기어드 모터의 응용 예로는 카메라에 사용되고 있는 필름 자동 감기 장치, 자동차의 시동 모터, 전동 드라이버, 그 밖에 큰 토크를 필요로 하는 여러 가지 장치에 폭넓게 사용되고 있다. 또 기어드 모터의 종류로는 래크와 피니언을 물리게 한 직진 운동(왕복 운동)형, 윔 기어형, 유성 기어형 등이 있다.

 

12) 스캐너용 모터

 

모터의 명칭은 전원의 종류, 구조, 크기, 성능, 사용 목적 등에 의해 여러 가지 호칭법이 있는데 여기서 설명하느 스캐너용 모터는 사용 목적에 의한 명칭이다. 정보 기기에서는 스캐너라고 하는 말을 자주 듣게 되는데 이것은 모터의 회전축에 폴리건 미러(다면 거울)를 설치하고 이 거울로 레이저 빔을 선모양으로 달리게 하는 주사장치이다. 스캐너용 모터는 사용 목적에 의한 분류이기 때문에 모터의 구조와 직접적인 관계가 없다. 그러나 그 요구 정밀도가 매우 엄격하기 때문에 모터이면 어떤 것이나 좋다고 할 수 없다. 따라서 스태너용 모터로 사용되는 것은 AC 구동의 싱크로너스 모터(히스테리스 싱크로너스 모터)나 DC 구동의 브러시리스 모터에 한정되어 있다. 어느 것이나 엄격한 지터 특성이 요구되고(0.01% 이하), 또 모터 설치부, 미러 설치부에도 엄밀한 가공 정밀도(수 micro meter)가 요구된다. 이 모터는 스캐너용 이외에 레이저 프린터, 복사기, 팩시밀리 등에도 사용되고 있다.

 

13) 인코더 부착 모터

 

인코더를 간단히 설명하면 여러가지 정보를 보호화 하는 일종의 변환기라고 말할 수 있다. 인코더의 종류에는 그 구조에 따라 리니어식 인코더, 로터리식 인코더가 있으며 각각 리니어 모터, 회전형 모터에 사용되고 있다. 기타 인코더의 기능 분류로서는 인크리멘터리형과 앱솔루트형이 있다. 인크리멘터리형은 회전축의 회전 각도를 출력 펄스의 형으로 변환하는 방식이고 한편 앱솔루트형은 회전축의 위치를 2진 또는 2진화 10진수 등의 부호로 변환하는 방식이다. 또 인크리멘터리형은 회전량의 변화는 검출할 수 있으나 절대적인 위치는 검출할 수 없다. 이 때문에 Z 축 신호를 별개로 빼내고 여기에서의 변화를 카운트하여 정확한 위치를 구하도록 연구되어 있다. 이와 같은 인코더가 부착되어 있는 모터를 인코더 부착 모터라고 한다. 인코더의 역할은 회전축에 설치된 슬릿 원판(부호판)의 회전에 의해 A, B, C상의 회전 신호를 빼내고 이들의 신호에서 정확한 위치, 회전량, 속도 제어를 하는 것인데, 인코더 부착 모터는 일종의 서보모터라고 할 수 있다. 또 인코더 부착 모터의 주요한 용도는 공업용 로봇, 공작 기계, 가종 제어 장치 등에 폭넓게 사용되고 있다. 

 

센서 설명 

 

IR 센서

 

사물에서 방출되는 적외선을 측정하는 센서를 말합니다. 적외선 센서는 적외선을 발생시키는 발광부와 적외선을 감지하는 수신부로 나뉘며, 발광부에서 나온 적외선이 물체에 반사되어 수광부에 들어오는 양에 따라 변하는 전압을 측정하는 방식으로 활용합니다.

 

엔코더

 

엔코더는 모터에 장착하는 센서로 다른 센서처럼 외부를 감지한다기보다는 모터 자체를 감지하는 방식으로 작동합니다. 보통 인코더는 두 개의 자석 센서를 한 쌍으로 사용하는데 이러한 이유는, 모터가 회전할 때 엔코더가 모터의 회전부를 감지할 때를 1 감지하지 못할 때를 0이라 했을 때 두 개의 엔코더가 감지하는 순서에 따라서 회전 방향이나, 회전속도 등을 측정할 수 있기에 엔코더는 자석 센서 두 개를 한 쌍으로 사용합니다. 

 

블루투스

 

블루투스는 짧게는 수 미터에서 길게는 수십 미터 정도의 거리를 두고 정보기기 사이에 전파를 사용해서 정보를 송수신해서 전달받는 데 사용됩니다. 이러한 정보의 전달을 위해서 정보기기는 보내고자 하는 데이터를 전자기파로 변환하여 송신하고 받는 정보기기 측에서 다시 전자기파를 데이터로 변환해서 받아들입니다. 이때 블루투스는 주파수를 사용해서 통신하므로 여러 개의 블루투스가 켜져 있으면 혼선이 생기는 문제가 생길 수 있습니다. 

 

로봇 팔 

 

매니퓰레이터의 작동범위를 통한 분류 수업에서의 로봇팔의 움직임에 있어서 움직일 수 있는 좌표계를 각각 R과 P로 구분하여서 표현합니다. 이러한 표현은 직선적으로 움직이는 앞뒤 움직임 관절을 P로, 점을 기준으로 원형으로 회전하는 관절을 R로 표현합니다. 이러한 관절이 3개있는 기준으로 구분을 할 때 각각의 좌표형에 따라서 직각좌표형(PPP), 원통좌표형(RPP), 극좌표형(RRP), 수직관절형(RRR), 스카라형(RPP)등이 있습니다. 

 

Kinematics 운동학 

 

좌표계

 

Kinematics를 사용하기 위해서는 우선 좌표계를 설정해야 하는데 이러한 좌표계를 설정할 때는 기본적으로 로봇에서 모터를 기준점으로 잡고 설정합니다. 모터를 기준점으로 설정하고 좌표계를 생성해야 이후 프로그래밍으로 통해서 좌표를 잡을 때 처리가 훨씬 간단해지기 때문입니다.

 

Kinematics

 

Kinematics는 두 가지로 사용되는데, Forward Kinematics와 Inverse Kinematics로 전자는 로봇의 관절 각도를 통해서 끝점의 좌표를 알아낼 수 있도록 해주고, 후자는 로봇의 끝 좌표를 통해 로봇의 각도를 알아낼 수 있습니다. 이 두 가지를 통해서 최종적으로 회전했을 때 모터의 도착점을 알 수 있어 모터가 회전해야 하는 각도나 회전 방향을 정해주어서 목표하는 작업을 수행하도록 만들 수 있습니다. 

 

follower 전체 모습

 

follower 실체 모습

 

코드 전체를 아래에 올려둡니다. 단, 여러 부분 코드가 합쳐져 있으므로 구분해서 사용해야 합니다.

 

receive_right_sum
/*******************************************************************************
  Copyright 2016 ROBOTIS CO., LTD.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*******************************************************************************/

#include <Dynamixel2Arduino.h>

// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL soft_serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_DUE) // When using DynamixelShield
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_ZERO) // When using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_OpenCM904) // When using official ROBOTIS board with DXL circuit.
#define DXL_SERIAL   Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (Serial1 for the DXL port on the OpenCM 9.04 board)
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 22; //OpenCM9.04 EXP Board's DIR PIN. (28 for the DXL port on the OpenCM 9.04 board)
#elif defined(ARDUINO_OpenCR) // When using official ROBOTIS board with DXL circuit.
// For OpenCR, there is a DXL Power Enable pin, so you must initialize and control it.
// Reference link : https://github.com/ROBOTIS-GIT/OpenCR/blob/master/arduino/opencr_arduino/opencr/libraries/DynamixelSDK/src/dynamixel_sdk/port_handler_arduino.cpp#L78
#define DXL_SERIAL   Serial3
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 84; // OpenCR Board's DIR PIN.
#else // Other boards when using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif


const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;
/*
  int c_m_1 = 0; //오른쪽 팔(lx-320)            //체크용 모터
  int c_m_2 = 0;
  int c_m_3 = 0;
  int c_m_4 = 0; //오른쪽 손(lx-320)
  int c_m_5 = 0;
  int c_m_6 = 0;
  int c_m_7 = 0; //왼쪽 팔(lx-320)
  int c_m_8 = 0;
  int c_m_9 = 0;
  int c_m_10 = 0; //왼쪽 손(lx-320)
  int c_m_11 = 0;
  int c_m_12 = 0;*/
int c_m[6] = {0,};
/*
  int m_13 = 0;   //오른쪽 팔(mx-28)            //몸체
  int m_14 = 0;
  int m_15 = 0;
  int m_16 = 0;   //오른쪽 손(lx-320)
  int m_17 = 0;
  int m_18 = 0;
  int m_19 = 0;   //왼쪽 팔(mx-28)
  int m_20 = 0;
  int m_21 = 0;
  int m_22 = 0;   //왼쪽 손(lx-320)
  int m_23 = 0;
  int m_24 = 0;
*/
int m_go[6] = {0,};
int check = 0;
byte tx_data[22];
byte checksum = 0;

void setup() {
  // put your setup code here, to run once:

  // Use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(1000000);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(1000000);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);

  // Turn off torque when configuring items in EEPROM area

  for (int i = 13; i < 25; i++)
  {
    dxl.torqueOff(i);
    dxl.setOperatingMode(i, OP_POSITION);
    dxl.torqueOn(i);
  }

  // Limit the maximum velocity in Position Control Mode. Use 0 for Max speed
  //dxl.writeControlTableItem(PROFILE_VELOCITY, DXL_ID, 30);
  for (int i = 13; i < 25; i++)
  {
    dxl.writeControlTableItem (PROFILE_VELOCITY, i, 50);
    delay(100);
  }
  Serial2.begin(57600);
  Serial.println(dxl.getPortBaud ());
}

bool rcv_status = 0;
bool rcv_ready = 0;
byte rcv_data = 0;
byte rcv_checksum = 0;
byte rx_buffer[13];
byte rx_data[12];
int rcv_count = 0;
int rcv_index = 0;

void loop() {
  // put your main code here, to run repeatedly:

  // Please refer to e-Manual(http://emanual.robotis.com/docs/en/parts/interface/dynamixel_shield/) for available range of value.
  // Set Goal Position in RAW value
  //중앙 2047 최대 4095 최소 0
  // dxl.torqueOff(7);
  if (rcv_status) {
    rcv_status = 0;
    for (int a = 0; a < 6; a++) {
      memcpy((char*)&m_go[a], (char*)&rx_data[a * 2], 2);
    }
    for (int a = 0; a < 6; a++) {
      Serial.print(m_go[a]);
      Serial.print(", ");
    }
    Serial.println();
    for (int a = 0; a < 3; a++) {
      dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지
    }
    for (int a = 3; a < 6; a++) {
      if(m_go[a] < 1000){
       dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지 
      }
    }
  }
}

void serialEvent2() {
  rcv_data = Serial2.read();
  //Serial.println(rcv_data);
  switch (rcv_count) {
    case 0:
      if ((rcv_ready == 0) && (rcv_data == 0xFF)) {
        rcv_count = 1;
      }
      else
        rcv_count = 0;
      break;
    case 1:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 2;
      }
      else
        rcv_count = 0;
      break;
    case 2:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 3;
        rcv_ready = 1;
      }
      else
        rcv_count = 0;
      break;
    case 3:
      rx_buffer[rcv_index] = rcv_data;
      rcv_index++;      //13번 받아야함 0 ~ 12
      if (rcv_index > 12) {
        /*
        rcv_checksum = 0;
        for (int i = 0; i < 12; i++) {
          rcv_checksum ^= rx_buffer[i];
        }
        rcv_checksum += 1;
        if (rcv_checksum == rx_buffer[rcv_index - 1]) {
          */
          rcv_status = 1;   //정상 수신 완료
          //Serial.print("yes");
          memcpy((char*)rx_data, (char*)rx_buffer, 12);
          /*
        }
        */
        rcv_count = 0;
        rcv_index = 0;
        rcv_ready = 0;
      }
      break;
    default:
      rcv_count = 0;
      rcv_index = 0;
      rcv_ready = 0;
      break;
  }
}

send_right_sum
/*******************************************************************************
  Copyright 2016 ROBOTIS CO., LTD.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*******************************************************************************/

#include <Dynamixel2Arduino.h>


// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL soft_serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_DUE) // When using DynamixelShield
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_ZERO) // When using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_OpenCM904) // When using official ROBOTIS board with DXL circuit.
#define DXL_SERIAL   Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (Serial1 for the DXL port on the OpenCM 9.04 board)
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 22; //OpenCM9.04 EXP Board's DIR PIN. (28 for the DXL port on the OpenCM 9.04 board)
#elif defined(ARDUINO_OpenCR) // When using official ROBOTIS board with DXL circuit.
// For OpenCR, there is a DXL Power Enable pin, so you must initialize and control it.
// Reference link : https://github.com/ROBOTIS-GIT/OpenCR/blob/master/arduino/opencr_arduino/opencr/libraries/DynamixelSDK/src/dynamixel_sdk/port_handler_arduino.cpp#L78
#define DXL_SERIAL   Serial3
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 84; // OpenCR Board's DIR PIN.
#else // Other boards when using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif


const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;
/*
  int c_m_1 = 0; //오른쪽 팔(lx-320)            //체크용 모터
  int c_m_2 = 0;
  int c_m_3 = 0;
  int c_m_4 = 0; //오른쪽 손(lx-320)
  int c_m_5 = 0;
  int c_m_6 = 0;
  int c_m_7 = 0; //왼쪽 팔(lx-320)
  int c_m_8 = 0;
  int c_m_9 = 0;
  int c_m_10 = 0; //왼쪽 손(lx-320)
  int c_m_11 = 0;
  int c_m_12 = 0;*/
int c_m[6] = {0,};
/*
  int m_13 = 0;   //오른쪽 팔(mx-28)            //몸체
  int m_14 = 0;
  int m_15 = 0;
  int m_16 = 0;   //오른쪽 손(lx-320)
  int m_17 = 0;
  int m_18 = 0;
  int m_19 = 0;   //왼쪽 팔(mx-28)
  int m_20 = 0;
  int m_21 = 0;
  int m_22 = 0;   //왼쪽 손(lx-320)
  int m_23 = 0;
  int m_24 = 0;
*/
int m_go[6] = {0,};
int check = 0;
byte tx_data[22];
byte checksum = 0;

void setup() {
  // put your setup code here, to run once:

  // Use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(1000000);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(1000000);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);

  // Turn off torque when configuring items in EEPROM area
  for (int i = 1; i < 13; i++)
  {
    dxl.torqueOff(i);
  }
  Serial2.begin(57600);
  Serial.println(dxl.getPortBaud ());
}

void loop() {
  // Set Goal Position in RAW value
  //중앙 2047 최대 4095 최소 0
  // dxl.torqueOff(7);
  check = 0;
  for (int a = 0; a < 6; a++) {
    c_m[a] = dxl.getPresentPosition(a + 7);
  }
  for (int a = 0; a < 3; a++) {
    if (c_m[a] != 0) {
      check = 1;
      break;
    }
  }
  if (check == 1)
  {
    for (int a = 0; a < 3; a++) {
      m_go[a] = map(c_m[a], 0, 1023, 0, 4095);
    }
    m_go[3] = map(c_m[3], 512, 819, 205, 512);
    m_go[4] = map(c_m[3], 512, 819, 205, 760);
    m_go[5] = map(c_m[3], 512, 819, 205, 700);
    pack();
  }
}

void pack() {
  tx_data[0] = 0xff;
  tx_data[1] = 0xf5;
  tx_data[2] = 0xf5;
  for (int a = 0; a < 6; a++) {
    memcpy(&tx_data[2 * a + 3], &m_go[a], 2);
    tx_data[2 * a + 4] &= 0x0F;
  }
  /*
    for(int a=3;a<15;a++){
    checksum ^= tx_data[a];
    }
    checksum +=1;
    tx_data[15] = checksum;
  */
  Serial2.write(tx_data, 15);
  for (int a = 0; a < 15; a++) {
    Serial.print(tx_data[a]);
  }
  Serial.println("");
}

send_left_sum
/*******************************************************************************
  Copyright 2016 ROBOTIS CO., LTD.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*******************************************************************************/

#include <Dynamixel2Arduino.h>

// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL soft_serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_DUE) // When using DynamixelShield
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_ZERO) // When using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_OpenCM904) // When using official ROBOTIS board with DXL circuit.
#define DXL_SERIAL   Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (Serial1 for the DXL port on the OpenCM 9.04 board)
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 22; //OpenCM9.04 EXP Board's DIR PIN. (28 for the DXL port on the OpenCM 9.04 board)
#elif defined(ARDUINO_OpenCR) // When using official ROBOTIS board with DXL circuit.
// For OpenCR, there is a DXL Power Enable pin, so you must initialize and control it.
// Reference link : https://github.com/ROBOTIS-GIT/OpenCR/blob/master/arduino/opencr_arduino/opencr/libraries/DynamixelSDK/src/dynamixel_sdk/port_handler_arduino.cpp#L78
#define DXL_SERIAL   Serial3
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 84; // OpenCR Board's DIR PIN.
#else // Other boards when using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif


const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;
/*
  int c_m_1 = 0; //오른쪽 팔(lx-320)            //체크용 모터
  int c_m_2 = 0;
  int c_m_3 = 0;
  int c_m_4 = 0; //오른쪽 손(lx-320)
  int c_m_5 = 0;
  int c_m_6 = 0;
  int c_m_7 = 0; //왼쪽 팔(lx-320)
  int c_m_8 = 0;
  int c_m_9 = 0;
  int c_m_10 = 0; //왼쪽 손(lx-320)
  int c_m_11 = 0;
  int c_m_12 = 0;*/
int c_m[6] = {0,};
/*
  int m_13 = 0;   //오른쪽 팔(mx-28)            //몸체
  int m_14 = 0;
  int m_15 = 0;
  int m_16 = 0;   //오른쪽 손(lx-320)
  int m_17 = 0;
  int m_18 = 0;
  int m_19 = 0;   //왼쪽 팔(mx-28)
  int m_20 = 0;
  int m_21 = 0;
  int m_22 = 0;   //왼쪽 손(lx-320)
  int m_23 = 0;
  int m_24 = 0;
*/
int m_go[6] = {0,};
int check = 0;
byte tx_data[22];
byte checksum = 0;

void setup() {
  // put your setup code here, to run once:

  // Use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(1000000);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(1000000);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);

  // Turn off torque when configuring items in EEPROM area

  for (int i = 13; i < 25; i++)
  {
    dxl.torqueOff(i);
    dxl.setOperatingMode(i, OP_POSITION);
    dxl.torqueOn(i);
  }

  // Limit the maximum velocity in Position Control Mode. Use 0 for Max speed
  //dxl.writeControlTableItem(PROFILE_VELOCITY, DXL_ID, 30);
  for (int i = 13; i < 25; i++)
  {
    dxl.writeControlTableItem (PROFILE_VELOCITY, i, 50);
    delay(100);
  }
  Serial2.begin(57600);
  Serial.println(dxl.getPortBaud ());
}

bool rcv_status = 0;
bool rcv_ready = 0;
byte rcv_data = 0;
byte rcv_checksum = 0;
byte rx_buffer[13];
byte rx_data[12];
int rcv_count = 0;
int rcv_index = 0;

void loop() {
  // put your main code here, to run repeatedly:

  // Please refer to e-Manual(http://emanual.robotis.com/docs/en/parts/interface/dynamixel_shield/) for available range of value.
  // Set Goal Position in RAW value
  //중앙 2047 최대 4095 최소 0
  // dxl.torqueOff(7);
  if (rcv_status) {
    rcv_status = 0;
    for (int a = 0; a < 6; a++) {
      memcpy((char*)&m_go[a], (char*)&rx_data[a * 2], 2);
    }
    for (int a = 0; a < 6; a++) {
      Serial.print(m_go[a]);
      Serial.print(", ");
    }
    Serial.println();
    for (int a = 0; a < 3; a++) {
      dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지
    }
    for (int a = 3; a < 6; a++) {
      if(m_go[a] < 1000){
       dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지 
      }
    }
  }
}

void serialEvent2() {
  rcv_data = Serial2.read();
  //Serial.println(rcv_data);
  switch (rcv_count) {
    case 0:
      if ((rcv_ready == 0) && (rcv_data == 0xFF)) {
        rcv_count = 1;
      }
      else
        rcv_count = 0;
      break;
    case 1:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 2;
      }
      else
        rcv_count = 0;
      break;
    case 2:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 3;
        rcv_ready = 1;
      }
      else
        rcv_count = 0;
      break;
    case 3:
      rx_buffer[rcv_index] = rcv_data;
      rcv_index++;      //13번 받아야함 0 ~ 12
      if (rcv_index > 12) {
        /*
        rcv_checksum = 0;
        for (int i = 0; i < 12; i++) {
          rcv_checksum ^= rx_buffer[i];
        }
        rcv_checksum += 1;
        if (rcv_checksum == rx_buffer[rcv_index - 1]) {
          */
          rcv_status = 1;   //정상 수신 완료
          //Serial.print("yes");
          memcpy((char*)rx_data, (char*)rx_buffer, 12);
          /*
        }
        */
        rcv_count = 0;
        rcv_index = 0;
        rcv_ready = 0;
      }
      break;
    default:
      rcv_count = 0;
      rcv_index = 0;
      rcv_ready = 0;
      break;
  }
}

receive_left_sum
/*******************************************************************************
  Copyright 2016 ROBOTIS CO., LTD.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*******************************************************************************/

#include <Dynamixel2Arduino.h>

// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL soft_serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_DUE) // When using DynamixelShield
#define DXL_SERIAL   Serial
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_ZERO) // When using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL SerialUSB
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_OpenCM904) // When using official ROBOTIS board with DXL circuit.
#define DXL_SERIAL   Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (Serial1 for the DXL port on the OpenCM 9.04 board)
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 22; //OpenCM9.04 EXP Board's DIR PIN. (28 for the DXL port on the OpenCM 9.04 board)
#elif defined(ARDUINO_OpenCR) // When using official ROBOTIS board with DXL circuit.
// For OpenCR, there is a DXL Power Enable pin, so you must initialize and control it.
// Reference link : https://github.com/ROBOTIS-GIT/OpenCR/blob/master/arduino/opencr_arduino/opencr/libraries/DynamixelSDK/src/dynamixel_sdk/port_handler_arduino.cpp#L78
#define DXL_SERIAL   Serial3
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 84; // OpenCR Board's DIR PIN.
#else // Other boards when using DynamixelShield
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif


const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;
/*
  int c_m_1 = 0; //오른쪽 팔(lx-320)            //체크용 모터
  int c_m_2 = 0;
  int c_m_3 = 0;
  int c_m_4 = 0; //오른쪽 손(lx-320)
  int c_m_5 = 0;
  int c_m_6 = 0;
  int c_m_7 = 0; //왼쪽 팔(lx-320)
  int c_m_8 = 0;
  int c_m_9 = 0;
  int c_m_10 = 0; //왼쪽 손(lx-320)
  int c_m_11 = 0;
  int c_m_12 = 0;*/
int c_m[6] = {0,};
/*
  int m_13 = 0;   //오른쪽 팔(mx-28)            //몸체
  int m_14 = 0;
  int m_15 = 0;
  int m_16 = 0;   //오른쪽 손(lx-320)
  int m_17 = 0;
  int m_18 = 0;
  int m_19 = 0;   //왼쪽 팔(mx-28)
  int m_20 = 0;
  int m_21 = 0;
  int m_22 = 0;   //왼쪽 손(lx-320)
  int m_23 = 0;
  int m_24 = 0;
*/
int m_go[6] = {0,};
int check = 0;
byte tx_data[22];
byte checksum = 0;

void setup() {
  // put your setup code here, to run once:

  // Use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(1000000);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(1000000);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);

  // Turn off torque when configuring items in EEPROM area

  for (int i = 13; i < 25; i++)
  {
    dxl.torqueOff(i);
    dxl.setOperatingMode(i, OP_POSITION);
    dxl.torqueOn(i);
  }

  // Limit the maximum velocity in Position Control Mode. Use 0 for Max speed
  //dxl.writeControlTableItem(PROFILE_VELOCITY, DXL_ID, 30);
  for (int i = 13; i < 25; i++)
  {
    dxl.writeControlTableItem (PROFILE_VELOCITY, i, 50);
    delay(100);
  }
  Serial2.begin(57600);
  Serial.println(dxl.getPortBaud ());
}

bool rcv_status = 0;
bool rcv_ready = 0;
byte rcv_data = 0;
byte rcv_checksum = 0;
byte rx_buffer[13];
byte rx_data[12];
int rcv_count = 0;
int rcv_index = 0;

void loop() {
  // put your main code here, to run repeatedly:

  // Please refer to e-Manual(http://emanual.robotis.com/docs/en/parts/interface/dynamixel_shield/) for available range of value.
  // Set Goal Position in RAW value
  //중앙 2047 최대 4095 최소 0
  // dxl.torqueOff(7);
  if (rcv_status) {
    rcv_status = 0;
    for (int a = 0; a < 6; a++) {
      memcpy((char*)&m_go[a], (char*)&rx_data[a * 2], 2);
    }
    for (int a = 0; a < 6; a++) {
      Serial.print(m_go[a]);
      Serial.print(", ");
    }
    Serial.println();
    for (int a = 0; a < 3; a++) {
      dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지
    }
    for (int a = 3; a < 6; a++) {
      if(m_go[a] < 1000){
       dxl.setGoalPosition(a + 13, m_go[a]); //13부터 18까지 
      }
    }
  }
}

void serialEvent2() {
  rcv_data = Serial2.read();
  //Serial.println(rcv_data);
  switch (rcv_count) {
    case 0:
      if ((rcv_ready == 0) && (rcv_data == 0xFF)) {
        rcv_count = 1;
      }
      else
        rcv_count = 0;
      break;
    case 1:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 2;
      }
      else
        rcv_count = 0;
      break;
    case 2:
      if ((rcv_ready == 0) && (rcv_data == 0xF5)) {
        rcv_count = 3;
        rcv_ready = 1;
      }
      else
        rcv_count = 0;
      break;
    case 3:
      rx_buffer[rcv_index] = rcv_data;
      rcv_index++;      //13번 받아야함 0 ~ 12
      if (rcv_index > 12) {
        /*
        rcv_checksum = 0;
        for (int i = 0; i < 12; i++) {
          rcv_checksum ^= rx_buffer[i];
        }
        rcv_checksum += 1;
        if (rcv_checksum == rx_buffer[rcv_index - 1]) {
          */
          rcv_status = 1;   //정상 수신 완료
          //Serial.print("yes");
          memcpy((char*)rx_data, (char*)rx_buffer, 12);
          /*
        }
        */
        rcv_count = 0;
        rcv_index = 0;
        rcv_ready = 0;
      }
      break;
    default:
      rcv_count = 0;
      rcv_index = 0;
      rcv_ready = 0;
      break;
  }
}

 

Followbot 시연 영상

 

 

 

 

반응형