1. 제어주기

T/C2 사용 Overflow Interrupt Routine

 

2. 정규화

void Normalization(int array[], int max[], int min[]){ 
	double numerator = 0; // 분자
	double denominator = 0; // 분모
	
	for(int i = 0; i < 8; i++)
	{
		numerator = array[i] - min[i];
		denominator = max[i] - min[i];
		array[i] = (numerator / denominator) * 100; // ADC값 정규화
		if(array[i] <= 50) line[i] = 1; // 검은색이면 1 흰색이면 0으로 배열 line에 저장
		else line[i] = 0;
	}
}

 

3. 가중치

void Weighted_Data_Processing(){ // 가중치
	int j = 0;
	sigma_L = 0; // 좌측 ADC 가중치
	sigma_R = 0; //우측 ADC 가중치
	for(int i = 0; i < 4; i++) sigma_L -= (line[i] * (1<<(3 - i))); // -8, -4, -2, -1
	for(int i = 4; i < 8; i++) sigma_R += (line[i] * (1<<(i - 4))); // 1, 2, 4, 8
 	UART1_Transmit(' ');
	UART1_TransNum(sigma_R + sigma_L); // 총 가중치를 uart로 출력
}

 

4. 주행

while (1)
	{
		ADC_Receive(adc_array); // ADC값을 받아온다.
		
		if(button == 1) // 버튼을 한 번 누르면 ADC 최대 최소값 받음
		{
			PORTA = 0x55;
			for(int i = 0; i < 8; i++)
			{
				if(adc_array[i] > adc_max[i]) adc_max[i] = adc_array[i];
				if(adc_array[i] < adc_min[i]) adc_min[i] = adc_array[i];
			}
		}
		else if(button >= 2) // 버튼을 한 번 더 누르면
		{
			PORTA = ~(1 << flag);
			Normalization(adc_array, adc_max, adc_min); // 정규화
			line_s = 0;
			for(int i = 0; i < 8; i++)
			{
				UART1_Transmit(line[i] + 48); // 각 센서가 검은줄 위에 있는지 0/1로 uart로 출력
				line_s += line[i]; // 검은줄 위에 있는 수발광 센서의 수
			}
			if((sigma_L + sigma_R) != 0) uturn = MOTOR_Direction((sigma_R + sigma_L), line_s, uturn); // 가중치 가 0이 아닐 경우 모터 방향 변경
			//uturn = MOTOR_Direction((sigma_R + sigma_L), line_s, uturn); // 수정
			// 문제점 1. 가중치가 0일 경우를 제외하였기 때문에 직진을 바르게 하지 못했음.
		}
		UART1_Transmit(' '); // 띄어쓰기
		Weighted_Data_Processing(); // 가중치
		UART1_Transmit(13); // uart 줄넘김
	}

 

<Github>

https://github.com/Myoung-Jisoo/Line-Tracer

<2021년도 상반기>

광운대학교 BARAM이라는 동아리의 활동으로 진행한 프로젝트입니다.

깃허브

 

1. 주제 선정 동기

 예전에는 1년에 한 번꼴로 병원에 방문하여 정기검진을 통해서만 내 몸의 변화를 볼 수 있었지만, 최근 몇 년 사이 우리 주변에 붙어있는 Mobile device들을 통한 정보수집이 편리해지면서 병원 밖에서 이루어지는 Health care 역시 중요해졌다. 그리고 인류의 기대 수명이 증가하면서 건강의 대표적인 키워드는 장수가 아닌 건강수명으로 변화하게 되었다.

* 건강수명 : 평균수명에서 질병이나 부상으로 인하여 활동하지 못한 기간을 뺀 기간

 

 이에 따라 지속적인 건강 관리에 사람들이 관심을 가지게 되었고, 그에 필요한 아이템들의 수요가 증가하게 되었다. 하지만, 많은 사람들이 제대로 운동을 배우고 지속적하는 것을 버거워해 작심삼일로 끝나고는 한다. 이를 위한 해결책으로 미국 하버드 헬스에서 소개한 전문가의 조언들을 아래에 간추려 놓았다.

 

 운동의 재정의 : 운동의 핵심은 심박수가 올라가는 것, 운동에 편하게 접근하자.목표조절 : 매일 21분씩만 운동해도 WHO의 일주일 권장 시간(150분 이상)에 도 달할 수 있다. 목표를 낮춰 조금이라도 운동을 하도록 노력해보자.동료 : 함께 운동할 수 있는 동료가 있으면 꾸준히 할 수 있다.

나는 이 중 운동을 재정의에 집중하여, 운동을 시작하는 진입장벽을 낮추기 위해 Health Manager 프로그램을 만들어보고자 하게 되었다.

 

현재 Play StoreApp Store에 나와있는 어플리케이션 중에서 카메라는 활용된 경우는 많지 않고 일정 시간 간격으로 카운트를 해주는데 그쳐 피드백이 이루어지지 않는다는 문제점이 있다고 생각했다. 그래서 하나의 카메라를 통해 운동을 인식하여 자동 카운트 해주고, 운동 속도에 대한 피드백을 계속해서 해주는 방식으로 개선을 하는 데에 목표를 잡았다.

 

지금은 학부생 수준에서의 프로젝트기에 시중에서 사용하기에는 부족하겠지만, 데이터 축적이나 나아가서는 이 프로젝트에서 몇가지 영상처리와 딥러닝 네트워크와 모델들을 공부해 이용해 보고, Digiter Health Care 분야에 활용할 수 있는 방법을 모색해보는 기회를 만들고자 한다.

Open Pose를 이용한 Key Point Detection & Skelton 생성 https://www.arxiv-vanity.com/papers/1812.08008/

 특히나 지난 학기에는 Open Pose라는 ModelKey Point Detection한 결과를 이용했다면, 이번에는 Model을 구현해보면서 Object detectionTracking 원리를 이해하고, 홈트레이닝에서 하는 주된 운동 중 쉽게 할 수 있는 하체운동인 스쿼트의 측정을 목표로 잡아 이번 프로젝트를 실현해보겠다.

 

2. 목표

 카메라로 스쿼트의 앉은 자세와 선자세를 구별해서 스쿼트 개수를 자동으로 (음성으로) 세주는 시스템을 구현한다.

 

3. System Architecture

 

개발 환경 : Ubuntu 18.04

 

Human Key Point Detection

 이 프로젝트에서는 사람 한 명의 동작을 추정하는 것이 중요하기 때문에 사람을 먼저 인식한 후에 key points를 추출하는 Top-down(하향식) 방법을 이용할 계획이다.

 먼저 Segmentation을 통해 영상의 이미지에서 사람이 있는 영역만 RoI로 지정을 해줄 것이다.

보통 Human key point tracking을 할 때, CNN(Convolutional Neural Networks)을 기반으로 한 특징 추출 model을 이용하는데, 프로젝트의 목표가 pose estimation system을 기반으로 하기 때문에 Mask R-CNN을 사용할 것이다.

여기서 Mask R-CNN은 하향식 keypoint estimation modelResNet을 확장시킨 framwork를 말한다. 표준적인 기반이 CNN²ResNet으로 구성되며 이미지의 특징을 추출하는데 사용된다. Mask R-CNN의 구조는 다음과 같다.

MASK R-CNN의 네트워크 구조 https://ganghee-lee.tistory.com/40

Resize Input image

 기존 Segmentation을 만들어진 Mask R-CNN³에서는 backcone으로 ResNet-101을 사용하는데 ResNet 네트워크에서는 input imagesize800~1024일 때 성능이 좋다고 알려져 있다. 따라서 이미지를 binear interpolation을 사용해 resize 해주고 네트워크 input size(1024 x 1024)에 맞게 나머지 값들은 zero padding으로 채워준다.

 

Backbone ResNet-101

  Mask R-CNN에서는 Backbone으로 ResNet-101 모델을 사용한다.

모델의 layer가 너무 깊어질수록 오히려 성능이 떨어지는 현상이 발생하는데, 그 이유가 gradient vanishing/exploding 문제 떄문에 학습이 잘 이루어지지 않기 때문이다.

 여기서 gradient vanishing이란 layer가 깊어질수록 미분을 점점 많이 하기 때문에 backpropagation을 해도 앞의 layer일수록 미분값이 작아져 그만큼 output에 영향을 끼치는 weight 정도가 작아지는 것을 말한다. 이 문제를 해결하기 위해 고안된 것이 ResNet이다.

 ResNet이전의 이미지 classification과 같은 문제의 경우 x에 대한 타겟값 y는 사실 x를 대변하는 것으로 yx의 의미가 같게끔 mapping해야 한다. , H(x)-x 를 최소화하는 방향으로 학습을 진행해야 하는 것이다.

 이 때, F(x) = H(x) - x 를 잔차라고 하며 이 잔차를 학습하는 것을 Residual learning이라 한다.

 

 위의 두 가지 그림을 보자. 왼쪽 그림처럼 네트워크의 outputx가 되도록 한다. 하지만 오른쪽 그림은 마지막에 x를 더해주어 네트워크의 output0이 되게끔 하는 것을 볼 수 있다. ResNet은 오른쪽 그림과 같이 mapping해서 최종 outputx가 되도록 학습한다.

 네트워크는 0이 되도록 학습시키고 마지막에 x를 더해서 H(x)x가 되도록 학습하면 미분을 해도 x자체는 미분값 1을 갖기 때문에 layer마다 최소 gradient1은 갖도록 한 것이다.

 

FPN (Feature Pyramid Network)

이미지 출처 :  FPN  https://ganghee-lee.tistory.com/40

 마지막 layer의 feature map⁶에서 점점 이전의 중간 feature map들을 더하면서 이전 정보까지 유지할 수 있도록 한다. 이렇게 함으로써 모두 동일한 scale의 anchor를 생성하게 되고, 작은 feature map에서는 큰 anchor를 생성하여 큰 object, feature map에서는 다소 작은 anchor를 생성하여 작은 objectdetect할 수 있도록 설계되었다.

 특히 마지막 layer에서의 feature map에서 이전 feature map을 더하는 것은 아래와 같이 Upsampling을 통해 이루어진다.

이미지 출처 :  FPN  https://ganghee-lee.tistory.com/40

 2배로 upsampling을 한 후 이전 layerfeature map1x1 Fully convolution 연산을 통해 filter개수를 똑같이 맞춰준 후 더함으로써 새로운 feature map을 생성한다.

 

RPN (Region Proposal Network)

 RPNinput 값은 이전 CNN 모델에서 뽑아낸 feature map인데, feature map에서 1scaleanchor를 생성하므로 결국 각 pyramid feature map마다 scale 1x ratio 3= 3개의 anchor를 생성한다. Region proposal을 생성하기 위해 feature map위에 nxn windowsliding window를 시키면서 object의 크기와 비율이 어떻게 될지 모르므로 k개의 anchor box를 미리 정의해놓는다.

 여기서 나온 anchor boxbounding box가 될 수 있기 때문에 미리 box 모양 k개를 정의해놓는 것이다. (위의 사진에서는 가로세로길이 3종류 x 비율 3종류 = 9개의 anchor box를 이용한다.)

 여기서 나온 anchor box를 이용하여 classificationbbox regression(delta)을 먼저 구하고 이 값에 anchor 정보를 연산해서 원래 이미지에 대응되는 anchor bounding box 좌표값으로 바꿔주게 된다.

 

NMS (Non-maximum-suppression)

 원래 이미지에 anchor 좌표를 대응시킨 후에는 각각 normalized coordinate로 대응시킨다. (FPN에서 이미 각기 다른 feature map 크리를 갖고 있기 때문에 모두 통일되게 정규좌표계로 이동시키는 과정) 그러면 결과는 아래의 왼쪽 사진과 같이 나타난다.

NMS 처리 전후 / 이미지 출처 : https://ganghee-lee.tistory.com/40

 각 object마다 대응되는 수십개의 anchor 중에서 장 classification score가 높은 anchor를 제외하고 다른 anchor들을 지운다.

 NMS알고리즘은 anchor bounding box들을 score순으로 정렬시킨 후 score가 높은 bounding box부터 다른 bounding boxIoU(Intersection Over Union)를 계산한다.

 이때 IoU가 해당 bounding box0.7이 넘어가면 두 bounding box동일 objectdetect한 것이라 간주하여 score가 더 낮은 bounding box는 지우는 식으로 동작한다. 최종적으로 각 객체마다 score가 가장 큰 box만 남게되고 나머지 box는 제거하게 되면 오른쪽 사진과 같이 하나의 bounding box만 남게 되는 것이다.

 

RoI align

 RoI pooling을 진행했을 때 발생하는 위치정보 왜곡 문제를 해결하기 위해 align을 이용한다. align은 각각의 RoI 영역에 대해 4개의 sample point에 대해 bilinear interpolation을 수행하고, 그 결과에 대해 max 또는 average로 합치는 것을 말한다.

RoI align / 이미지 출처 : https://ganghee-lee.tistory.com/40

더보기

<참고 자료>

- “작심삼일 끝! 홈트레이닝에 실패하는 이유와 해결책”, 정운경(운동전문가), 2021.02.05

https://www.hidoc.co.kr/healthstory/news/C0000577681

 

운동, 작심삼일 넘어서려면, 코메디 닷컴 (이용재 기자), 2021.03.15.

http://kormedi.com/1335629/%EC%9A%B4%EB%8F%99-%EC%9E%91%EC%8B%AC%EC%82%BC%EC%9D%BC-%EB%84%98%EC%96%B4%EC%84%9C%EB%A0%A4%EB%A9%B4/

 

Simple Baselines for Human Pose Estimation and Tracking, Microsoft Research Asia, University of Electronic Science and Technology of China (21 Aug 2018)

 

Detect-and-track: Efficient Pose Estimation in Videos, The Robotics Institute, Carnegie Mellon University (2 May 2018)

 

Deep High-Resolution Representation Learning for Human Pose Estimation, University of Science and Technology of China (25 Feb 2019)

 

[Pose Estimation] Human Pose Estimation 최신 연구 동향

https://eehoeskrap.tistory.com/329

 

신경망을 이용한 인간 행동인식(action recognition) 연구동향 2D CNN / 3D CNN

https://m.blog.naver.com/PostView.nhn?blogId=khm159&logNo=222027509486&proxyReferer=https:%2F%2Fwww.google.com%2F

 

Overview of Human Pose Estimation Neural Networks HRNet + HigherHRNet, Architectures and FAQ 2d3d.ai

https://towardsdatascience.com/overview-of-human-pose-estimation-neural-networks-hrnet-higherhrnet-architectures-and-faq-1954b2f8b249

 

Convolution, 멈춤보단 천천히라도

https://webnautes.tistory.com/1044

 

MASK R-CNN 정리

https://mylifemystudy.tistory.com/82

 

Faster R-CNN

http://incredible.ai/deep-learning/2018/03/17/Faster-R-CNN/#:~:text=Region%20of%20Interest%20Pooling,-RPN%EC%9D%B4%ED%9B%84%2C%20%EC%84%9C%EB%A1%9C&text=%EC%84%9C%EB%A1%9C%20%EB%8B%A4%EB%A5%B8%20%ED%81%AC%EA%B8%B0%EB%9D%BC%EB%8A%94%20%EB%A7%90,%EB%8B%A4%EB%A5%B8%20%ED%81%AC%EA%B8%B0%EB%9D%BC%EB%8A%94%20%EB%9C%BB%EC%9E%85%EB%8B%88%EB%8B%A4.&text=%EC%9D%B4%EB%95%8C%20%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%20%EA%B8%B0%EB%B2%95%EC%9D%B4,Pooling(ROI)%20%EA%B8%B0%EB%B2%95%EC%9E%85%EB%8B%88%EB%8B%A4.

 

(논문리뷰) R-CNN 설명 및 정리

https://ganghee-lee.tistory.com/35

 

CNN(Convolutional Neural Network)

https://hobinjeong.medium.com/cnn-convolutional-neural-network-9f600dd3b395

 

CNN, Convolutional Neural Network 요약

http://taewan.kim/post/cnn/#:~:text=Convolution%20Layer%EC%9D%98%20%EC%9E%85%EB%A0%A5%20%EB%8D%B0%EC%9D%B4%ED%84%B0,%EA%B3%84%EC%82%B0%EC%9C%BC%EB%A1%9C%20%EB%A7%8C%EB%93%A4%EC%96%B4%EC%A7%84%20%ED%96%89%EB%A0%AC%EC%9E%85%EB%8B%88%EB%8B%A4.

 

(논문리뷰&재구현) Faster R-CNN 설명 및 정리

https://ganghee-lee.tistory.com/37

 

Object Tracking 이란?

https://mickael-k.tistory.com/26

 

ResNet

https://ganghee-lee.tistory.com/41

 

선형 보간법(linear, bilinear, trilinear interpolation)

https://darkpgmr.tistory.com/117

Upsampling

https://m.blog.naver.com/PostView.nhn?blogId=worb1605&logNo=221266339261&proxyReferer=https:%2F%2Fwww.google.com%2F

 

할당 문제 & 헝가리안 알고리즘 (Assignment Problem & Hungarian Algorithm)

https://gazelle-and-cs.tistory.com/29

 

탐욕(그리디) 알고리즘(greedy algorithm)

https://www.zerocho.com/category/Algorithm/post/584ba5c9580277001862f188

 

Anchor box

https://jungnamgyu.tistory.com/54

 

detection 연구 Anchor box ? region proposal 자세한 원리

https://study-grow.tistory.com/entry/detection-%EC%97%B0%EA%B5%AC-Anchor-box-region-proposal-%EC%9E%90%EC%84%B8%ED%95%9C-%EC%9B%90%EB%A6%AC

 

컴퓨터비전에서의 기본 용어 및 개념 정리

https://ganghee-lee.tistory.com/33

 

딥러닝에서 이미지 classification, localization, detection, segmentation

http://egloos.zum.com/javalove/v/1227428

 

Cython

https://cython.readthedocs.io/en/latest/src/quickstart/overview.html

 

Easydic

https://romillion.tistory.com/53

 

PyYAML

https://rfriend.tistory.com/540

 

Pandas

https://doorbw.tistory.com/172

 

올바른스쿼트자세 힙업운동 시작하세요!

https://m.blog.naver.com/topilsan5189/221278110905

 

<2020년도 하반기>

광운대학교 BARAM이라는 동아리의 활동으로 진행한 프로젝트입니다.

깃허브 https://github.com/Myoung-Jisoo/Robot-Arm-using-OpenPose

 

1. 주제 선정 동기

 전자의수족에 관심이 있어 종종 관련자료들을 찾아보고는 했습니다. 외부상황을 인식해 장갑형태의 로봇손, 절단부위의 잔존근육에서 발생하는 미세한 생체신호(근전도 신호)를 이용하여 컨트롤을 하는 등의 기술 등을 볼 수 있었습니다. 하지만 모든 사람들의 팔 상하단, 손바닥크기 손가락 마디들의 길이가 같지 않듯이, 사람들의 움직임 역시 일반화할 수 없을 것이라는 의문이 들었습니다. 그리고 한 사람의 팔의 움직임을 가장 유사하게 구사할 수 있는 것은 신체 비율이 비슷한 반대쪽 팔이지 않을까 싶은 생각을 가지게 되었습니다. 이에 영상처리를 이용하여 왼팔의 움직임을 읽어 그 정보를 로봇팔(왼쪽)로 전송해 오른팔과 움직임과 비슷하게 구현해내자는 목표를 설정하게 되었습니다.

 

2.  목표

- 카메라는 한 대만 사용

Open Pose가 한 프레임을 받아오는 시간이 결코 짧지 않기 때문에, 한 대를 사용하는 것이 효율적이라고 생각했습니다.

 

- 주먹 쥐었다 펴기

손가락을 5개의 모터를 이용해 다 제어하기에는 하드웨어 무게가 감당이 되지 않을 것 같았습니다. 그래서 서보모터 하나만 사용하여 주먹을 쥐었다 펴는 동작을 구현하고자 했습니다.

 

- 팔꿈치 아래인 팔 하안부 동작 구현

팔꿈치 부분의 모터 2개를 연결해주어야 아래의 1. 팔을 돌리는 동작 / 2. 팔을 구부리는 동작 을 구현하고 싶었습니다.

팔 동작

하지만 팔을 돌리는 동작의 경우 z축을 회전시켜 똑같이 구현하려 하게 된다면, 카메라 두 대가 필요했습니다. 그래서 오른쪽의 그림과 같이 모터를 수직으로 연결하는 방식으로 프로젝트를 진행해보기로 결정하게 되었습니다.

 

3.  Hardware Architecture

하드웨어 구상

 손 부분의 3D 모델링은 Thingivers에서 가져왔고 그 외 부분 모델링은 INVENTOR를 사용했습니다.

 

사용모터 스펙 :

RDS5160 65x30x48 무게 : 162g
동작전압 : 6.0V ~ 8.4V
동작속도(6V) : 0.17sec/60°
동작속도(7.4V) : 0.15sec/60°
동작속도(8.4V) : 0.13sec/60°
토크(6V) : 58kg/cm
토크(7.4V) : 65kg/cm
토크(8.4V) : 70kg/cm
회전각도 : 360°

 

4.  System Architecture

System Architecture

 

 

Open Pose 환경구축

https://myoungziis-study.tistory.com/category/%ED%99%98%EA%B2%BD%EA%B5%AC%EC%B6%95/Open%20Pose

 

'환경구축/Open Pose' 카테고리의 글 목록

진로를 위해 공부하고 있는 내용들을 정리하는 블로그입니다.

myoungziis-study.tistory.com

 

'BARAM 동아리 프로젝트 > 동작을 따라하는 2-DOF Robot Arm' 카테고리의 다른 글

[Atmega128] 서보모터 제어  (0) 2021.08.05
[Hardware] 손 만들기  (0) 2021.08.05
OpenPose로 좌표값 받아오기  (2) 2021.08.05
완성작  (0) 2021.08.05

1. 서보모터

 서보모터를 제어하기 위해서는 20ms의 간격으로 1~2ms 폭의 펄스(사각파)를 생성 해야 하며, 펄스의 폭에 의해서 각도가 정해집니다. 구동 범위가 0~180°인 서보모터의 경우 아래와 같이 최소값을 1.0ms 최대값을 2.0ms로 잡고 백분위를 이용해 계산하여 제어를 할 수 있습니다.

 이번 프로젝트에서 사용하는 RDS5160의 경우에는 360° 구동이 가능한 모터이기 때문에 0°를 1.0ms, 그리고 360°를 2.0ms로 계산하면 됩니다.

 

2. 360도 서보모터 제어하기

 서보모터는 Timer 3의 Fast PWM mode를 이용해 주기를 맞춰주었습니다.

 

[main.c]

#include "mcu_init.h"

int cnt = 0;
int adc_array[8] = {0, };
int i = 0;
float servo1 = .080;
float servo2 = .075;
int duty1, duty2;
// duty 2.5~12.5

int num1 = 0;
int num2 = 0;
char a = 13;
int flag;
int number = 0;
int sign = 0;
// UART 통신

ISR(TIMER2_OVF_vect)
{
	cnt++;
	TCNT0 = 131;	// 4ms
	
	a = UART1_Receive();
	
	if(a == ',')
	{
		if(sign == 1) num1 = -num1;
		flag = 1; sign = 0;
	}
	else if(a == 13)
	{
		if(sign == 1) num2 = -num2;
		flag = 2; sign = 0;
	}
	
	if(flag == 0) Receive_num1();
	else if(flag == 1) Receive_num2();
	else if(flag == 2)
	{
		UART1_TransNum(num1);
		UART1_Transmit(',');
		UART1_TransNum(num2);
		UART1_Transmit(13);
		
		if((num1 >= 40) && (num1 <= 110)) servo1 = (double)num1 / 1000;
		if((num1 >= 35) && (num1 <= 105)) servo2 = (double)num2 / 1000;
		
		num1 = 0; num2 = 0; flag = 0;
	}
	
	MOTOR_Direction(servo1, servo2);
	
	if(cnt == 25) // 100ms
		cnt = 0;
}


void Receive_num1() // 첫번째 수를 입력받는다.
{
	num1 *= 10;
	number = a - 48;
	if(a == '-') sign = 1;
	if((number >= 0) && (number <= 9)) num1 += number;
}

void Receive_num2() // 두번째 수를 입력받는다.
{
	num2 *= 10;
	number = a - 48;
	if(a == '-') sign = 1;
	if((number >= 0) && (number <= 9)) num2 += number;
}

ISR(INT0_vect) // 인터럽트 0번 발생시 1번 서보모터 duty비 80%
{
	servo1 = .080;
}

ISR(INT1_vect) // 인터럽트 1번 발생시 2번 서보모터 duty비 75%
{
	servo2 = .075;
}

int main(void)
{
	UART1_INIT();
	Timer2_INIT();
	BUTTON_INIT();
	SERVO_MOTOR_INIT();
	ADC_INIT();
	
	sei();
	
	while(1);
}

터미널을 통해 두 모터의 duty값 전송

 서보모터가 UART 통신을 통해 수신받은 값으로 잘 움직이는 것을 확인할 수 있었습니다. 그러나, 속도는 조절할 수 없다는 단점 때문에 움직임이 뚝뚝 끊겨보이는 문제가 생겼습니다.

 이 문제는 다음과 같이 서보모터가 목표값에 도달할 때까지 제어주기마다 1씩 OCR값을 변화시켜주는 방법으로 해결할 수 있었습니다.

	if(abs(OCR3C - (1250 * servo1)) > 1) {
		if(OCR3C < (1250 * servo1)) OCR3C += 1;
		else if(OCR3C > (1250 * servo1)) OCR3C -= 1;
	}
	if(abs(OCR3B - (1250 * servo2)) > 1) {
		if(OCR3B < (1250 * servo2)) OCR3B += 1;
		else if(OCR3B > (1250 * servo2)) OCR3B -= 1;
	}

'BARAM 동아리 프로젝트 > 동작을 따라하는 2-DOF Robot Arm' 카테고리의 다른 글

프로젝트 기획  (0) 2021.08.05
[Hardware] 손 만들기  (0) 2021.08.05
OpenPose로 좌표값 받아오기  (2) 2021.08.05
완성작  (0) 2021.08.05

손은 Thingiverse에서 찾은 파일을 사용했습니다. (손 모델링 파일은 아래 링크에서 받았습니다.)

https://www.thingiverse.com/thing:242639

 

Flexy-Hand by Gyrobot

A proof of concept printable hand with "live hinge" flexible joints. Individually activated fingers using Filaflex filament as tendons. Printed in Makerbot Translucent Red and Filaflex hinges. Re-mix this idea into your own robotic or prosthetic project. F

www.thingiverse.com

 

 그래서 왼쪽 사진과 같이 출력해서 조립해주었는데... 안 움직입니다.

 애초에 조립이 제대로 되지도 않았고, 생각을 잘못했던 게 구조상 실을 당겼다 놓으면 다시 손이 펴져야 하는 구조인데, 탄성이 없으니 돌아올리가 없었습니다.

 

 그래서 무엇을 사용할 지 고민을 하다가 몰드용 액상 실리콘을 사용하게 되었습니다. 실리콘을 구매하는 것 자체가 처음인지라, 인터넷을 찾아보고 구매하고 직접 사용해보면서 경도를 맞춰나갔습니다.

실리콘을 마디에 넣어 사용한 모습

 위의 사진은 아래 경도 25의 실리콘을 사용하였을 때의 모습입니다. 움직임이 부드럽지만, 탄성이 떨어져 사용에는 부적합하다 판단했습니다.

 다음으로는 경도 40의 실리콘을 사용하였으나, 역시나 탄성이 부족한 느낌이 들어 사용하기에는 어렵다는 생각이 들었습니다.

 

 마지막으로 선택하게 된 게 퍼티형 실리콘이였습니다. 액상실리콘의 경화시간이 너무 긴데다가 시간이 얼마 남지 않아 내린 결론이었습니다. (경도 60정도의 실리콘을 사용하고 싶었으나 구매처를 찾지 못했습니다.)

 

 결과적으로는 실리콘 퍼티가 가장 적당하다고 생각은 들었으나, 신율이 작은 것인지, 너무 많이 늘어나면 부서지는 모습을 보여서 아쉬웠습니다. 판매처에 경도와 경화시간 외에 다른 정보들이 없어 고려하지 못했으나, 경도보다는 신율와 수축율을 중점적으로 고려했으면 더 좋았을거라는 아쉬움이 남았습니다.

  경도 인장강도 신율 수축율 경화시간
shore A MPa % %
몰드몬스터 25 25 >= 3.2 >= 500 >= 0.3 180
몰드몬스터 하드 40 >= 4 >= 450 >= 0.3 300
몰드용 실리콘퍼티 70       6
더보기

- 경도 : 규정 하중하에서 표면이 규정된 크기에 압침 침입에 저항하는 정도

- 인장강도 : 표준시편을 일정한 강도로 잡아당겼을 때, 절단되는 힘 또는 응력

- 신율(신장율) : 시험 표준편에 가해지는 인장력에 의해 늘어나는 길이로 초기 길이에 대한 백분율

* 아래 블로그 포스팅를 참고했습니다.

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dy_chun&logNo=140023575560 

 

실리콘 고무의 특성

>> 실리콘고무의 개요 고무는 유용한 특성들을 독특하게 조합시켜 나타내는 복잡한 물질이다. 그 중 ...

blog.naver.com

 

 

'BARAM 동아리 프로젝트 > 동작을 따라하는 2-DOF Robot Arm' 카테고리의 다른 글

프로젝트 기획  (0) 2021.08.05
[Atmega128] 서보모터 제어  (0) 2021.08.05
OpenPose로 좌표값 받아오기  (2) 2021.08.05
완성작  (0) 2021.08.05

 OpenPose에서 제공해주는 예제 코드를 활용했고, visual studio로 Serial 통신을 하는 코드는 다른 분이 뚫어두신 코드를 활용했습니다.

 

전체 코드는 너무 길어 깃허드 링크로 걸어두었습니다.

https://github.com/Myoung-Jisoo/Robot-Arm-using-OpenPose/blob/main/Visual%20studio%202017/openpose.cpp

이미지의 Keypoints의 좌표를 띄운 모습

이미지의 각 좌표가 나타난 모습입니다.

 

그리고 OpenPose 기본 예제코드인 openpose demo의 실행결과는 다음과 같습니다.

OpenPose 실행결과

 영상에서 보시다시피 튀는 값들이 보입니다. 필터처리가 필요해 보입니다. 때문에 아래와 같이 미디언 필터를 이용해 처리했습니다. (연속으로 들어온 다섯개의 값들을 정렬 후에 가운데 값 사용)

			if (filter > 5) {
				filter = 0;
				// 크기순 정렬
				sort(shoulderX.begin(), shoulderX.end());
				sort(shoulderY.begin(), shoulderY.end());
				sort(elbowX.begin(), elbowX.end());
				sort(elbowY.begin(), elbowY.end());
				sort(wristX.begin(), wristX.end());
				sort(wristY.begin(), wristY.end());
				// 중간값 담기
				if ((abs(shoulder.x - shoulderX.at(2)) < 10) && (abs(shoulder.y - shoulderY.at(2)) < 10)) shoulder_count++;
				if (shoulder_count > 4) {
					f_shoulder.x = shoulder.x;
					f_shoulder.y = shoulder.y;
				}
				else {
					shoulder.x = shoulderX.at(2);
					shoulder.y = shoulderY.at(2);
					//shoulder_count = 0;
				}

				if ((abs(elbow.x - elbowX.at(2)) < 20) && (abs(elbow.y - elbowY.at(2)) < 20)) elbow_count++;
				if (elbow_count > 4) {
					f_elbow.x = elbow.x;
					f_elbow.y = elbow.y;
				}
				else {
					elbow.x = elbowX.at(2);
					elbow.y = elbowY.at(2);
				}

				wrist.x = wristX.at(2);
				wrist.y = wristY.at(2);
				// vector 비우기
				shoulderX.clear();
				shoulderY.clear();
				elbowX.clear();
				elbowY.clear();
				wristX.clear();
				wristY.clear();
			}

 

그리고 위에서 얻은 데이터들을 토대로 아래와 같이 각 서보모터의 값들을 구한 후에 Uart통신을 통해 atmega128로 전송해주었습니다.

void getAngleAndSend() {
	angle1 = acos(downLength / downLength_Max);

	
	//double dz = downLength * tan(angle1);
	//double a = sqrt(pow(dx2, 2) + pow(dz, 2));

	angle2 = asin((f_elbow.x - wrist.x) / downLength_Max);

	if ((elbow.y - wrist.y) > 0) angle1 = 3.14 - angle1; // 1.5708은 90도

	std::string angle = std::to_string((int)(angle1 * (180.0 / 3.14))) + "," + std::to_string((int)(angle2 * (180.0 / 3.14)));

	op::opLog("\n" + angle);

	angle = "s" + angle + "e";

	char Angle[100];
	strcpy(Angle, angle.c_str());

	if (uart.isOpen()) {
		op::opLog("connected!");
		uart.Write(Angle, angle.length());
	}
	else op::opLog("not connected :(");
}

'BARAM 동아리 프로젝트 > 동작을 따라하는 2-DOF Robot Arm' 카테고리의 다른 글

프로젝트 기획  (0) 2021.08.05
[Atmega128] 서보모터 제어  (0) 2021.08.05
[Hardware] 손 만들기  (0) 2021.08.05
완성작  (0) 2021.08.05

1. 최종 하드웨어

완성한 모습

 

2. 동작영상

동작 영상

+ Recent posts