[아두이노] MPU-6050 + Stepper Motor 제어

IOT/아두이노|2019. 5. 15. 09:00

[아두이노] MPU-6050 + Stepper Motor 제어



MPU-6050 가속도/자이로 센서를 그냥 끝내기가 아쉬워서 간단히 실제 뭔가를 움직이게 하는 실험을 하면 좋을 것 같아서 오늘 Post 주제로 결정했습니다. 복잡한 제어는 아니고 간단히 원리만 이해하는 차원으로 하나의 패턴 동작만 수행하도록 제어하는 코딩을 실험 할 예정입니다. 설정은 MPU-6050 모듈의 기울기 각도 중 하나 X축의 각도값에 따라 Stepper Motor를 회전 시키는 조건입니다. 이 회전은 각도의 변화 크기에 따라 회전시키는 각의 결정하는 명령입니다. 즉, X축의 기울기 각도가 커지면 커질수로 회전의 각도 변화는 크게 회전시키고 X축의 기울기 각도가 작아지면 작아질수로 회전의 각도 변화는 작게 회전 시킵니다. 여기서, X축의 기울기가 반대로 기울려졌을 때는 역방향으로 회전 시키게 됩니다.

복잡한 설정을 하면 코딩량이 늘어나고 오히려 가독성이 떨어지고 의미 전달이 되지 않기 때문에 간단히 MPU-6050 모듈의 기울기에 따라서 Stepper Motor의 회전각을 제어하는 실험입니다. 이 원리를 꼭 기억해 두셨다가 나중에 이 원리를 회전의 속도로 변형해서 실험 해보세요. 그리고 드론에서의 x,y,z 회전각을 통해서 4개의 Motor의 회전 속도 제어를 통한 수평 조절에 대한 구상을 머리속에서 상상 코딩을 해보세요.

그러면, MPU-6050 모듈로 Stepper Motor를 제어하는 실험을 해보겠습니다.


1. MPU-6050 + Stepper Motor 회로도




2. 코딩



1) 기본 소스


[기본베이스 소스] - GetAngle (tockn님 소스 기반)

#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);
void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu6050.begin();
  //mpu6050.calcGyroOffsets(true);
   mpu6050.setGyroOffsets(0.75, 0.05, 0.05);
}
void loop() {
  mpu6050.update();
  int val=mpu6050.getAngleX();
  Serial.println(angle); 
}

mpu6050.setGyroOffsets(0.75, 0.05, 0.05);

여기서, 위 인자값은 mpu6050.calcGyroOffsets(true) 함수로 사전에 계산된 값입니다.

지난시간 복습차원으로 다시 설명 드리면, 처음에는 setGyroOffsets()함수는 주석 처리하고 calcGyroOffsets()함수의 주석을 풀고 해당 찍히는 값을 출력해 주세요. 거기서 측정 된 값은 GyroOffsets값을 메모장에 다 적어놓고 setGyroOffsets() 함수의 인자값으로 넣으면 사전에 calcGyroOffsets()함수에서의 계산 시간을 줄일 수 있습니다.

아래 그림은 MPU6050_tockn 라이브러리의 GetAngle를 돌렸던 결과 이미지 입니다. 지난시간의 이미지인데 약간 위 코딩의 인자값하고 다른데, 처음 측정된 위치가 다르기 때문에 해당 값은 다를 수 밖에 없습니다.


지금 다시 측정을 하면 위치가 좀 달라지면 또 다른 값으로 바뀌겠지요. 원래는 계산하면 좋지만 빠르게 실험을 하기 위해서 한번 계산하고 그 값을 기준으로 세팅해놓고 실험하시면 빠르게 테스트 할 수 있습니다. 나중에 정교한 제어를 한다면 계산이 필요하겠지만 간단히, 원리 테스트에서는 처음 한번만 calcGyroOffsets()함수로 x,y,z GyroOffset 값을 구해 놓고 setGyroOffsets()함수에 인자로 넣고 두번째 부터는 빠르게 테스트 하는게 더 좋겠죠.

2) MPU-6050의 X축 회전각에 따른 Stepper Motor 회전


변화각 구해서 그 변화각 만큼 회전을 시켜 보자.

  int val=mpu6050.getAngleX();
  angle = angle + val-previousAngle;
  previousAngle=val;  
  stepper.step(angle);

val에서 우선 MPU-6050 모듈에서 X축의 회전각을 구하게 됩니다. 현재의 회전각은 val에 저장됩니다. 여기서, previousAngle 변수는 이전 getAngleX() 각을 저장되어 있습니다. 매 loop()함수가 돌 때마다 getAngleX() 각을 previousAngle 변수에 저장합니다.

그러면,

현재 X회전각 - 이전X회전각 = X회전각의 변화값

이렇게 얼마만큼의 변화가 발생했는지 그 차이 값을 구할 수 있게 됩니다.

이때,

angle = angle + val-previousAngle;

이렇게 하면 angle은 X회전각의 변화값을 누적하는 변수입니다. + 방향으로 변화각이 계속 커질 때 angle의 값은 그 변화각만큼 계속 증가하게 되고 만약에 - 방향으로 변화각이 계속 변할때 그 변화각만큼 angle의 값은 그 변화각 만큼 계속 감소하게 됩니다.

stepper.step(angle);

그리고, angle을 Stepper Motor의 회전각으로 설정하면 그 방향 각도만큼 정방향 회전이나 역방향 회전을 하게 됩니다.

참고로, 위 stepper.step(angle)에서 angle은 스템수입니다. 즉 180값이라고 하면 180도 회전하는게 아닙니다. 180 스템수만큼 정방향으로 회전 시키는 것일 뿐입니다. 180도 만큼의 회전을 주고 싶다면 1024스템수로 회전 시켜야 합니다.

stepper.step(map(angle,0,360,0,2048));

이렇게 되어야 정상적인 각도 회전이 되겠죠.

3) Stepper Motor


#include <Stepper.h>

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup() {
 stepper.setSpeed(12); 
}
void loop() {
 stepper.step(angle);
}

헤더파일, Stepper 객체변수 선언하고 setup()함수안에서 stepper.setSpeed() 로 스피드를 설정합니다. 그리고 나서 실제적으로 Stepper Motor를 stepper.step() 함수로 실제 회전을 시키게 됩니다. 이 코딩 부분은 위에 MPU-6050의 코딩과 합쳐야 겠죠.

4) 코딩 합치기


#include <Stepper.h>
#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);
int angle = 0;
int previousAngle=0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu6050.begin();
  //mpu6050.calcGyroOffsets(true);
  mpu6050.setGyroOffsets(0.75, 0.05, 0.05);
  stepper.setSpeed(12); 
}
void loop() {
  mpu6050.update();
 
  int val=mpu6050.getAngleX();
  angle = angle + val-previousAngle;
  previousAngle=val;  
     
  stepper.step(angle);
  Serial.println(angle); 
  delay(50);
}

삽입해야 할 위치에 코딩을 배치하면 됩니다. 완성된 소스는 좀 복잡해 보일 수 있지만 각 부품에 대해 의미만 제대로 이해하고 있다면 해당 위치에 삽입하는데 어려움이 없을 거라 생각 됩니다.

3. 실험 결과


아래 움짤 이미지는 회전각의 변화를 시리얼모니터로 출력한 결과물입니다. MPU-6050의 X축 회전각의 변화가 실제 Stepper Motor에 회전각의 값이 어떻게 변화되는지 잘 살펴보세요.



다음은 실제 MPU-6050모듈을 움직일 때 X축 회전각에 의해 Stepper Motor 회전되는 모습입니다.

마무리


간단히 MPU-6050 모듈에서 측정된 X축 회전각의 값을 통해서 Stepper Motor를 회전 시켰습니다. 여기서, 중요한 것은 MPU-6050의 값이 다른 부품의 움직임을 만들었다는 것이고 그것을 코딩으로 표현했다는데 의미가 있습니다.

오늘 실험은 Stepper Motor를 움직이게하는 첫발을 내딛는 코딩입니다. 여기서 부터 여러분들이 코딩에 살을 붙여가면서 상상력을 동원해서 뭔가를 하나씩 추가해보셨으면 합니다.

첫발은 내딛는데까지는 안내해드렸고 두번째 발은 어려분들이 내딛을 차례입니다.
한번 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] Stepper Motor에 대해 상상하다.

IOT/아두이노|2019. 5. 5. 09:00

[아두이노] Stepper Motor에 대해 상상하다.



Steem.js에 재미를 붙여서 실험하고 있어서 아두이노 post가 늦어지고 있네요. 지난주의 Stepper Motor 제어를 집중적으로 다뤘는데 오늘 post는 실제 구현은 안해 봤지만 상상한 내용을 post에 담아 이야기를 하고자 합니다. Stepper Motor는 각도를 제어하는 Motor 입니다. 각도를 제어 한다는 것은 회전을 프로그래머가 설계한 방향으로 회전을 시킬 수 있다는 의미입니다. 원하는 위치로 회전을 시킬 수 있고 회전 된 각도의 값을 알 수 있다면 이것을 이용하여 많은 것들을 표현 할 수 있습니다.

원하는 각도로 회전 시킨다는 것은 정방향 100도 회전 시킬 수 있고, 역방향 -500도로 회전 시킬 수 있으며 회전하면서 회전 각도를 저장해 놓으면 현재 Stepper Motor가 어느 방향으로 몇도 회전 되어 있는지 알 수 있습니다. 이 정보로 우리들은 뭘 할 수 있을까요. 산업 현장에서는 산업 로봇이 자동으로 나사를 조이고 용접하고 물건을 나르는 등의 움직임을 제어하는 데 사용 됩니다. 조립을 하는 과정에서 나사를 몇 바뀌 회전 시켜야 하는지 각도값으로 제어할 수 있습니다. 그리고 산업 로봇팔이 용접을 할 때 용접 할 위치로 산업 로봇팔의 관절이 회전하면서 해당 위치로 이동하겠죠. 즉, 움직임을 표현하는데 각도제어 Motor가 사용 되고 각도를 제어를 할 수 있는 Stepper Motor는 많은 것들을 할 수 있게 됩니다.

오늘 다룰 내용은 움직임을 각도로 나눠서 초음파 센서로 거리를 측정하고자 합니다. 이렇게 얻은 거리 정보를 토대로 초음파 센서에서 감지된 대상의 좌표 (x,y,z) 꼭지점을 구하고자 합니다. 그리고 구한 꼭지점을 processing으로 시각화 하는 상상을 해 보았습니다. 실제 구현은 못해 봤습니다. 사실 딴거에 빠져서 구현은 안했습니다. 그냥 상상한 내용을 담아 이야기 하고자 합니다.

1. 거리 측정 회로도


  • 준비물 : 스템모터, 모터드라이버, 초음파센서, 아두이노우노


대충 위와 같은 형태로 구성한다고 상상을 해 봤습니다. 이렇게 하면 Stepper Motor가 1도씩 회전을 한다면 어떻게 될까요. 각도에 따른 거리를 측정 할 수 있게 됩니다.


위 그림처럼 원통에 거리 측정기를 넣고 측정을 시작한다고 가정을 해 봅시다. 그러면 원통의 벽면까지의 거리값을 구할 수 있겠죠. 여기서, 360도를 1도씩 회전하면서 거리를 측정한다고 상상을 해보세요. 측정되어 나온 원통까지의 거리값을 이용하여 꼭지점(x,y,z)를 구할 수 있습니다. 그 꼭지점을 연결하면 단층 이미지를 만들어 낼 수 있습니다. 이 단층 이미지가 여러장이 쌓이면 3D Rendering 을 통해서 실제 원통 모양으로 이미지를 만들어 낼 수 있겠죠.

오늘 실험은 얻어진 좌표 (x,y,z) 꼭지점을 연결하여 processing에 배치시켜 3D 단층 이미지를 만드는 과정을 상상을 해보고자 합니다. 그 과정을 이제부터서 진행 하겠습니다.

2. 거리 측정에 따른 좌표 꼭지점 구하기



위 x,y,z 좌표계가 있다면 원점은 Stepper Motor의 회전하는 중심 지점이 되겠죠. (x,z)축의 평면 방향으로 초음파 센서가 1도씩 회전을 한다면 위 그림처럼 360도의 360개의 좌표 지점을 만들어 낼 수 있게 됩니다. y축은 아두이노의 초음파가 붙어있는 위치가 되며 초음파가 측정하는 각도에 방향에 따라 (x,z)축의 거리 꼭지점을 아래의 공식에 의해서 구할 수 있습니다.


그러면 (x,z)축으로 펼쳐서 보면 위 그림 처럼 나타나고 Stepper Motor의 회전 angle이 되고 초음파 측정 거리는 r이 되어 이 r과 angle의 값을 기준으로 꼭지점 (x,z)를 구할 수 있습니다. 오랫만에 접하는 수학이라서 기억도 안나고 손 놓은지가 정말 오래만이라 공식도 기억 안나서 인터넷에서 찾았네요. 이제 이런것들을 수학적으로 계산하기에는 너무 벅차네요. 중학교 수준이지만요. 요즘 초등학생들이 배우는 수학인 것 같은데 잘 모르겠네요. 이정도 수학도 이제 벅차네요.

이렇게 해서 y축은 초음파의 고정 위치이니깐 고정 y꼭지점에서 Setpper Motor가 회전하는 angle에 따른 초음파의 거리(r)을 통해 x,z 꼭지점을 구하면 원점에서 1도씩 회전 할때마다 좌표 (x,y,z)의 꼭지점을 구할 수 있게 됩니다.


좌표 (x,y,z)의 꼭지점 선으로 연결하면 이런 평면 이미지가 그려지겠죠.

3. processing으로 측정된 좌표를 연결


위에서 구한 좌표(x,y,z)의 꼭지점을 구하게 되면 processing으로 표현 한다면 어떤 느낌일까요.

다음과 예제를 보시기 바랍니다.

void setup() {  
    
    size(600,600,P3D); //창사이즈
    noStroke();  //테두리없음
} 

void draw() {  
    background(0); //배경색
    lights();  //조명

    pushMatrix();  //Start
    translate(300,270,300); //이동
    shape();
    popMatrix(); //End
}
void shape(){
  fill(0,255,0); //채우기
  beginShape();
  for(int i=0;i<=360;i++){
      vertex(cos(i)*100, 0, sin(i)*100);   
  }
  endShape(CLOSE);
}

위 예제는 for문을 유심히 보시기 바랍니다. 위 소스는 processing 3D 도형 제어 (아두이노) Post의 소스 수정을 최소화하여 표현 했습니다.

아두이노에서 processing과 시리얼통신을 할 수 있다고 했죠. 그러면 Stepper Motor가 1도씩 회전하면서 초음파 센서가 측정한 좌표 지점을 구한 (x,y,z) 꼭지점을 시리얼통신으로 전송한다면 그 값으로 beginShape()~endShape(CLOSE) 사이의 vertex(x,yz) 값을 시리얼통신으로 얻은 (x,y,z) 꼭지점으로 대체한다면 360도 회전할 때 360개의 꼭지점을 그리게 되면 평면 이미지를 만들 수 있게 됩니다.

위 소소는 100이라는 초음파 거리를 고정으로 초음파 거리 (r)에 대한 Stepper Motor 회전(angle)을 가상으로 주어진 상태에서 가상으로 이미지를 그리는 예제입니다.

4. processing으로 측정된 좌표 이미지 결과



위 결과는 가상 데이터 (x,y,z)의 값을 기준으로 그렸기 때문에 원형의 이미지를 얻었습니다. 실제로 구현을 한다면 불규칙적인 평면의 이미지를 얻을 수 있겠죠.

5. 이것로 뭘 만들까?


순간 떠오르는 생각을 상상력으로 구현은 안했지만 글로써 표현을 했습니다. 이걸로 뭘 만들 수 있을까요. 일상에서 이런 표현들이 뭐가 있을까요. 이 글을 쓰는 순간에 떠오르는 생각은 자율주행에서 360도 회전하는 센서에 주변 사물을 감지하는데 적용하게 좋겠죠.

그럼 또 뭘 할 수 있을까요. 거리측정센서로 3D 랜더링을 할 수 있을까? post에서 이야기한 3D 랜더링에 적용할 수 있습니다. 위 실험에 대한 상상한 내용은 하나의 평면 단층 이미지를 만들 수 있습니다. 그러면, 초음파 센서가 일렬로 여러개가 연결되어 있으면 여러장의 단층 이미지를 얻을 수 있겠죠. 아니면 Stepper Motor를 하나 더 제어해서 y축 회전 시켜서 y축 위치를 변경해 가면서 x,z 축의 단층 이미지 데이터를 얻을 수 있겠죠. 이렇게 여러개의 단층 (x,y,z)의 값을 얻을 수 있으면 이 데이터들을 서로 연결하면 3D 모형의 이미지 형태로 랜더링을 할 수 있습니다. 위 실험 자체만으로도 3D 좌표 평면 이미지로 표현 되었지만 좀더 Volume Rendering을 하려면 여러장의 이미지 데이터가 필요 합니다.

그외도 이야기를 하자면 끝도 없습니다. 오늘 제가 post한 내용들이 바로 상상 코딩입니다. 왜! 제가 post를 끝날 때마다 상상의 나래를 펼쳐 보라는 이유가 오늘 post의 담겨져 있습니다. 실제 구현을 안하더라도 우리는 일상의 사물을 보면서 또는 영화 속 SF장면을 떠올리면서 많은 상상을 할 수 있습니다. 그 상상이 아두이노의 소재가 되는 것이고 그 아두이노로 상상한 것들을 비슷하게 구현해 낼 수 있습니다.

실제로 구현을 안하더라도 가상으로 이렇게 상상 코딩을 할 수 있습니다.

마무리


여러분들도 상상 코딩을 생활화 해보세요. 뭔가 프로그램 언어를 배우고 정석으로 깊게 파고드는 것도 중요하지만 무엇보다 중요한 것은 상상 코딩입니다. 정석으로 전문 코딩을 하는 것은 엔지니어이지 개발자나 창작자가 아닙니다. 다소 코딩이 부족하더라도 뭔가에 대해서 상상하는 사람이 진정한 개발자이나 창작자입니다.

엔지니어는 반복학습하면 누구나 다 될 수 있지만 개발자나 창작자는 상상을 하지 않으면 되지 못합니다. 여러분들도 처음에 코딩을 전문적으로 정석 코스로 깊게 배우는 싶은 분들도 많을 꺼에요. 하지만 상상하지 않으면 의미가 없습니다.

마지막으로 여러분들도 위 내용이 아니더라도 아두이노 관련 부품이나 누가 표현한 원리 중 하나를 찾아서 그 원리를 다른 쪽으로 응용하여 상상해보는 시간을 가졌으면 합니다.

댓글()

[아두이노] Stepper 대신 Servo Motor로 가상시뮬레이터 실험

IOT/아두이노|2019. 5. 4. 09:00

[아두이노] Stepper 대신 Servo Motor로 가상시뮬레이터 실험



지난시간에 Stepper Motor 원하는 각도 회전과 블루투스 원격 제어 실험을 하였습니다. 이 부분을 아두이노가 없는 분들을 위해서 어떤 느낌인지 의미를 전달하고자 가상시뮬레이터로 표현을 해보았네요. 표현한 방식은 Servo Motor를 이용하여 아두이노 두대를 연결하여 시리얼통신을 통해서 Servo Motor를 제어하는 실험입니다. 가상시뮬레이터에서 Stepper Motor가 없기 때문에 직접 실험을 할 수 없습니다. 물론 DC 모터를 가지고 Stepper 라이브러리를 적용하여 억지로 표현하는 경우는 있지만 그렇게 표현하면 오히려 혼동을 야기 할 수 있으니 정석으로 지난 시간의 실험한 Stepper Motor 코딩 로직을 기반으로 Servo Motor를 대신 사용하여 실험을 진행했으며 위에 공개회로도 링킁 가셔서 가상시뮬레이터를 실행 시켜보세요. 온라인 상에서 체험 할 수 있을 거라 생각 됩니다.

이제 본격적으로 실험 내용을 다뤄 보겠습니다.

1. Servo Motor 회로도


  • 준비물 : Servo Motor 1개, 아두이노우노
  • 내용 : 10핀을 Servo Motor 출력핀으로 연결하시오.


간단하게 선 연결을 할 수 있겠죠.

1) 코딩


내용 : servo 라이브러리를 이용하여 아두이노 IDE의 시리얼통신 입력값에 의해 회전시키자.
참조 : [아두이노] Stepper Motor 원하는 각도 회전(1)


Servo Motor

#include <Servo.h>
Servo servo : 서보모터 객체 선언
servo.attach(서보핀) : 서보 모터에 출력을 담당할 핀 선언
servo.write(회전각) : 회전각 만큰 서보모터를 회전 시킴

시리얼 통신

  • Serial.begin(9600) : 시리얼 통신 시작(9600 통신속도)
  • Serial.println(값) : 시리얼모니터 출력
  • Serial.available() : 시리얼통신으로 데이터가 들어놨는지 상태 확인
  • Serial.parseInt() : Int형으로 데이터를 읽음

지난 시간의 Stepper Motor의 소스에서 그대로 가져왔습니다.

#include <Servo.h>

Servo servo;
int angle = 0;

void setup()
{
  Serial.begin(9600);
  servo.attach(10);  
  
  servo.write(angle);
  delay(50);
}

void loop()
{
    if(Serial.available()) {
      int val=0;
      char ch=Serial.read();
      if(ch=='a')val=1;      
      else if(ch=='d')val =-1;
      else val =0;
      
      angle+=val;
      
      if(angle>180) angle=180;
      else if(angle<0) angle=0;
        
      servo.write(angle);
      Serial.println(angle);      
      delay(50);
    }
}

Stepper Motor랑 코딩은 동일합니다. 단 if문이 하나 더 추가 되었는데 0~180도 사이 각으로 회전이 제한이 됩니다. 180도 이상과 0도 이하의 각도로 회전을 할 수 없습니다. 그래서 angle각이 180도를 넘으로 180도에 수렴하게 만들고 0도 이하가 나오면 0도에 수렴하게 만들어 놓았습니다. 그외는 코딩이 동일하기 때문에 따로 변경할 부분은 없습니다.

      if(angle>180) angle=180;
      else if(angle<0) angle=0;

위 문장만 잘 이해하시면 따로 설명은 필요 없겠죠. 지난 시간에 설명 했으니깐요. 아무튼 시리얼 모니터에서 'a'와 'd'를 입력하면 알파벳 키 값에 따라서 회전을 시키게 됩니다.

2) 결과



2. 2대의 아두이노 + Servo Motor 회로도


  • 준비물 : Servo Motor 1개, 아두이노우노 2개
  • 내용 : 10핀을 Servo Motor 출력핀으로 연결하고 Serial 통신을 하기 위해서 두대의 아두이노는 2,3빈으로 교차로 연결하라.

  • Rx - 데이터 읽기 (B arduino Pin3 =>A arduino Pin2)
  • Tx - 데이터 보내기(B arduino Pin2 =>A arduino Pin3)

한대는 스마트폰이라고 생각하고 다른 한대에 Servo Motor를 제어하는 실험입니다. 소스 코딩도 동일합니다. B 아두이노가 아래쪽 Servo Motor가 연결된 A 아두이노에 명령을 내리면 그 명령에 따라서 A 아두이노가 Servo Motor를 회전 하게 됩니다. Bluetooth 통신 소스와 동일합니다. 2대의 아두이노로 Bluetooth 실험을 대신한다고 생각하시면 됩니다.


1) 코딩



시리얼 통신

  • Serial.begin(9600) : 시리얼 통신 시작(9600 통신속도)
  • Serial.println(값) : 시리얼모니터 출력
  • Serial.available() : 시리얼통신으로 데이터가 들어놨는지 상태 확인
  • Serial.parseInt() : Int형으로 데이터를 읽음

SoftwareSerial 통신

#include <SoftwareSerial.h>

SoftwareSerial mySerial (rx, tx) : 소프트시리얼 객체선언(rx(수신), tx(전송))
mySerial.begin(9600) : 시리얼 통신 시작(예로 9600 통식속도를 사용해 봤네요.)
mySerial.write(값) : 데이터 전송
mySerial.available() : 데이터 들어왔는 확인
mySerial.read() : 전송된 데이터 1byte 읽기


[A 아두이노 코딩]

#include <Servo.h>
#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

Servo servo;
int angle = 0;

void setup()
{
  Serial.begin(9600);
  mySerial.begin(2400);
  servo.attach(10);  
  
  servo.write(angle);
  delay(50);
}

void loop()
{
    if(mySerial.available()) {
      int val=0;
      char ch=mySerial.read();
      
      if(ch=='a')val=1;      
      else if(ch=='d')val =-1;
      else val =0;
      
      angle+=val;
      
      if(angle>180) angle=180;
      else if(angle<0) angle=0;
        
      servo.write(angle);
      Serial.println(angle);      
      delay(50);
    }
}

[B 아두이노 코딩]

#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

void setup()
{
   Serial.begin(9600);
   mySerial.begin(2400);
}

void loop()     
{
  if(Serial.available()) {
    mySerial.write(Serial.read());      
  } 
}

2) 결과



마무리


Stepper Motor 회전을 Bluetooth를 이용하여 스마트폰에서 제어를 하는 실험을 지난 시간에 했었습니다. 그것을 가상시뮬레이터에서 최대한 같은 표현을 하기 위해서 두 대의 아두이노를 연결하여 한쪽에서 다른쪽으로 Motor 제어 명령을 보내고 Stepper Motor가 지원이 안됨으로 그 역활을 Servo Motor로 대신하여 회전시키는 실험을 하였습니다.

가상시뮬레이터에서 최대한 같은 느낌의 표현과 코딩을 그대로 적용함으로써 지난 시간에 배운 Stepper Motor 제어를 느낄 수 있게 표현 되어 있으니 한번 공개회로도 링크로 가셔서 체험을 해보세요.

이상으로 Stepper Motor Post를 마무리 합니다.

댓글()

[아두이노] Stepper Motor 원하는 각도 회전(2)

IOT/아두이노|2019. 5. 3. 09:00

[아두이노] Stepper Motor 원하는 각도 회전(2)



지난 시간에 Stepper Motor를 원하는 각도로 회전 시켰는데 오늘은 Bluetooth로 스마트폰에서 아두이노 연결 된 Stepper Motor를 회전 시키는 실험을 하도록 하겠습니다.


1. Stepper Motor + Bluetooth 통신 준비


스마트폰과 아두이노는 Bluetooth를 통해 통신합니다.


스마트폰 Bluetooth 어플은 아무거나 사용해도 됩니다. 실험에서는 Controller mode와 Terminal mode를 사용하여 실험 했네요. Controller mode은 버턴을 지정하고 버턴을 클릭하면 해당 버턴값을 아두이노로 보내는 형식이고요, Terminal mode은 채팅하는 식으로 아두이노 IDE 시리얼모니터에서 값을 입력하는 것과 유사합니다. 직접 전송할 값을 타이핑해서 보내는 방식입니다. 버턴을 눌러서 그 값을 전송하는 방식과 직접 타이핑해서 전송하는 방식이 들어 있는 어플이면 아무거나 상관 없습니다. 직접 앱인벤터로 만드셔도 되고요.


그냥 시리얼 통신으로 값을 전달할 수 있는 Bluetooth 어플이면 아무거나 상관 없습니다. 안드로이드면 구글스토어에서 Arduino Bluetooth만 치셔도 많은 어플들이 검색되니깐 실험하고 싶은 어플을 아무거나 선택하시면 됩니다.

2. Stepper Motor + Bluetooth 회로도



  • 준비물 : 5V 스템모터, ULN2003 모터드라이버, Bluetooth(HC-06) 1개, 아두이노우노
  • 내용 : 8,9,10,11핀을 순서대로 IN1, IN2, IN3, IN4에 연결하고 스템모터와 UNL2003 모터쉴드에 연결하고 Bluetooth를 2, 3번에 연결한다.

  • Rx - 데이터 읽기 (BlueRX =>arduino Pin3)
  • Tx - 데이터 보내기(BlueTX =>arduino Pin2)


지난 시간의 Stepper Motor 회로도에서 Bluetooth만 하나 더 연결한 회로도 입니다.

2. 코딩 - I



Stepper

#include <Stepper.h>
  • Stepper stepper(STEPS, IN1, IN2, IN3, IN4) : 사용하는 Stepper Motor 스템수, 각 4핀을 세팅.
  • stepper.setSpeed(값) : Stepper Motor의 속도 설정.
  • stepper.step(스텝수) : 스템수로 회전 각을 표현 한다.

시리얼 통신

  • Serial.begin(9600) : 시리얼 통신 시작(9600 통신속도)
  • Serial.println(값) : 시리얼모니터 출력
  • Serial.available() : 시리얼통신으로 데이터가 들어놨는지 상태 확인
  • Serial.parseInt() : Int형으로 데이터를 읽음

SoftwareSerial 통신

#include <SoftwareSerial.h>

SoftwareSerial mySerial (rx, tx) : 소프트시리얼 객체선언(rx(수신), tx(전송))
mySerial.begin(9600) : 시리얼 통신 시작(예로 9600 통식속도를 사용해 봤네요.)
mySerial.write(값) : 데이터 전송
mySerial.available() : 데이터 들어왔는 확인
mySerial.read() : 전송된 데이터 1byte 읽기


[지난 시간 소스]

#include <Stepper.h>

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup()
{
  stepper.setSpeed(12);
  Serial.begin(9600);
}

void loop()
{
   if(Serial.available()) {
    int val=Serial.parseInt(); //회전각 int형으로 읽기
    
    val=map(val,0,360,0,2048); //회전각 스템 수
    stepper.step(val);
    Serial.println(val);
    delay(10);
  }
}

위 소스를 가지고 수정을 합시다. Bluetooth 통신을 하기 위해서 SoftwareSerial 라이브러리를 이용하여 통신을 하게 됩니다 그래서, 다음과 같은 Bluetooth 통신 명령 과정이 필요합니다.

#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

이렇게 초기 선언을 합니다. 2번핀은 Bluetooth의 TX핀이고 3번핀은 Bluetooth의 RX핀입니다. 혼동하시면 안됩니다. 나머지 코딩은 Serial 단어를 mySerial로만 변경하시면 코딩 수정이 끝납니다. 변경되는 부분은 아래와 같습니다.

void setup()
{  
  mySerial.begin(9600);
}
void loop()
{
   if(mySerial.available()) {
    int val=mySerial.parseInt(); //회전각 int형으로 읽기
    mySerial.println(val);
    delay(10);
  }
}

합쳐진 코딩은,

#include <SoftwareSerial.h>
#include <Stepper.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup()
{
  stepper.setSpeed(12);  
  mySerial.begin(9600);  
}

void loop()
{
 
  if(mySerial.available()) {
    int val=mySerial.parseInt();
    val=map(val,0,360,0,2048);
    stepper.step(val);
        mySerial.println(val);
    delay(10);   
  }
}

[결과]
Terminal Mode로 값을 직접 타이핑 한 값으로 회전시키면 다음과 같은 결과가 나오네요. 360도를 보내면 아두이노가 Bluetooth로 받은 후 Stepper Motor를 회전시킨후 회전 시킵니다. 그리고 나서 스템수를 다시 스마트폰으로 보내고 스마트폰는 받은 스템수를 아래 이미지 처럼 "HC-06: 2048"이라고 출력 됩니다.


간단히 실험 영상을 보시기 바랍니다.


3. 코딩 - II


코딩-I은 스마트폰으로 각도를 채팅방식으로 입력을 해서 Stepper Motor를 회전 시켰다면 이제는 방향버턴키로 회전시키는 코딩으로 수정하도록 하겠습니다. 참고로 방향키버턴으로 눌러서 회전 시키면 위 코딩-I 소스대로 하면 문제가 좀 발생합니다. 그 이유는 mySerial.parseInt() 함수 때문에 그렇습니다. 만약에 각도 데이터를 전송하고 읽을때 읽는 데이터가 밀리면 통신 버퍼에 쌓이게 되고 그러면 합쳐진 상태로 각도를 읽는 문제가 발생합니다. 가령, 10도 회전을 연달아 이어서 10, 10 이렇게 전송이 되었을 때 받는 아두이노에서 데이터가 쌓여 1010이렇게 되면 parseInt()함수는 한번에 1010각도로 읽어버리게 됩니다. 즉, 10, 10 이렇게 회전 시켜서 20도를 회전 시켜야 하는데 1010 이것을 한번에 읽어서 1010각도로 회전 시켜버리는 문제가 생기게 됩니다. 그래서 방향키를 방향 알파벳 한글자로 해서 mySerial.read()로 1byte씩 읽고 그 값에 따라 회전시키는 방법으로 쉽게 제어할 수 있도록 코딩을 변경 하겠습니다.

코딩-1 소스에서,

  if(mySerial.available()) {
    int val=mySerial.parseInt();
    val=map(val,0,360,0,2048);
    stepper.step(val);
        Serial.println(val);
    delay(10);   
  }

이 부분만 변경하면 됩니다.

int angle = 0; //외부변수 현재 각도값
if(mySerial.available()) {
      int val=0;
      char ch=mySerial.read();

      if(ch=='a')val=10;      //시계방향
      else if(ch=='d')val=-10; //반시계방향
      else val=0;
      
      angle+=val;
      val=map(val,0,360,0,2048);  
      stepper.step(val);
      //Serial.println(angle);      
      delay(10);
}

if문으로 1byte 읽은 알파벳이 ch변수에 저장되고 이 저장된 변수가 'a'면 정방향 10도 회전, 'd'면 역방향 10도 회전시키고 그외 키 값은 무시 0도 회전으로 if문에서 체크하여 val 변수에 회전시킬 각도값을 저장하게 했습니다.

여기서 외부 변수로 angle에 대한 동작 명령은 코딩하지 않았습니다. 이것은 여러분들이 나중에 활용하라는 의미로 남겨 둔 변수입니다. 이 변수는 현재 코딩에서는 없어도 되는 변수이지만 구지 표현한 이유는 나중에 어려분들이 Stepper Motor를 회전을 제어할 때 꼭 필요한 변수이기 때문입니다. 예를 들면, 우리가 Stepper Motor 회전을 시키면 700도 정방향으로 회전 시켰다가 역방향 200도 회전 시키고 또 다시 정방향, 역방향 이렇게 계속 회전을 시킬 경우 Stepper Motor라 마지막 회전된 위치를 단순히 회전만 시키면 알 수 없습니다. 이때 angle이라는 변수를 하나 선언해 놓고 처음 회전이 시작한 위치를 0도에 지정해놓고 계속 회전 값들을 angle변수에 더하게 되면 Stepper Motor의 시작 위치 0도에서 어느 방향으로 회전을 하더라도 현재 회전한 위치를 알 수 있게 됩니다.

여기서, 한가지 예로 외부 입력값 E(End)라고 생각하고 위 if문에 연장 선상으로 if문으로 아래와 같이 코딩하면

else if(ch=='e') val = -angle;

이렇게만 표현하면 e키가 입력된 순간 angle의 변수 안에는 지금 까지 회전되어 진 현재의 위치각도를 가지고 있기 때문에 그 값에 -(마이너스)를 붙이면 원상태 0도로 되돌아 가게 됩니다. 즉, 90도가 현재의 위치면 -angle로 -90도 만큼 회전 하면 0이 되겠죠. 다시 -90도가 현재의 위치면 -(-90)이니깐 +90도 만큼 회전 하면 0이 됩니다. 결론은 e키가 입력되면 이 한줄로 처음 자신의 위치로 되돌아 가는 명령을 코딩할 수 있습니다.

angle의 변수를 남겨 둔 이유는 여러분들이 나중에 회전을 제어할 때 언제든지 자신의 위치로 되돌아 갈 수 있고 현재의 회전 된 위치 값을 가질 수 있으면 그 기준으로 특별한 회전을 제어할 수 있게 되기 때문에 이런 angle 변수가 중요하기 때문에 선언만 해놓았습니다. 나머지는 여러분들이 이 변수를 가지고 어떻게 활용할지는 여러분의 몫입니다.

종합해보면,

#include <Stepper.h>
#include <SoftwareSerial.h>

const int rxPin = 2;
const int txPin = 3;
SoftwareSerial mySerial(rxPin, txPin); // RX, TX

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

int angle = 0;

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  stepper.setSpeed(12); 
}

void loop()
{
  if(mySerial.available()) {
      int val=0;
    char ch=mySerial.read();
      if(ch=='a')val=10;      
      else if(ch=='d')val=-10;
      else val=0;
      
      angle+=val;
      val=map(val,0,360,0,2048);  
      stepper.step(val);
      Serial.println(angle);      
      delay(10);
    }
}

[결과]



Controller Mode를 누르면 위 그림처럼 버턴 이미지로 구성된 창이 뜹니다. 그리고 톱니모양 설정을 누르면 버턴 키 값을 지정할 수 있습니다. 게임 방향키값인 a,s,w,s키로 우선 설정했는데 실제 실험에서는 a,d키만 사용합니다. 이 키값을 통해서 Setpper Motor를 회전 시키게 됩니다.

간단히 스마트 폰으로 방향키를 누렀을 때 Stepper Motor가 회전되는 실험 영상입니다.

마무리


이렇게 해서 스마트폰으로 간단히 회전을 시키는 법을 배웠습니다. Bluetooth를 한번 소개한 뒤에 계속 중복된 실험이 이뤄지고 있는데 이런 실험 과정을 여러분들도 실험하면서 계속 반복 학습을 해주세요. 그래야 나중에 다른 부품을 사용하더라고 이 부품을 이전에 배웠던 부품들과 쉽게 연결할 수 있습니다. 어떻게 두 부품을 결합하고 두 부품의 소스 코딩을 어떻게 합쳐지고 코딩이 되는지 그 감각을 익히셨으면 합니다. 그리고 하나의 표현으로 끝내지 말고 다른 표현을 계속 머리속에서 상상하셔야 합니다. 처음에는 이게 힘들지만 나중에는 재밌는 놀이처럼 여러가지의 상상을 하게 됩니다.

그런데 처음 배우시는 분들은 Bluetooth로 통신하는 실험만 하고 끝나고 Stepper Motor 회전 실험만 하고 넘어 갑니다. 나주엥 어떤 주제로 작품을 만들려고 할 때 그 때부터 문제가 발생합니다. 두 개 이상의 부품을 합치는 실험을 할 때 회로도 표현은 그럭저럭 되는데 코딩부분은 둘을 합치는 방법 자체를 이해를 못하는 경우가 많기 때문에 여러분들은 처음 부품을 배울 때 그 부품을 다른 부품과 계속 연결해서 실험하셔야 나중에 어떤 부품이든지 쉽게 표현을 할 수 있게 됩니다.

오늘 실험은 Stepper Motor를 하나를 조정했지만 두개 이상 연결하면 RC카 또는 로봇팔 등의 구현이 가능하고 Stepper Motor은 다양한 관절 제어에 사용하니깐 한번 SF영화나 애니메이션에서 봤던 장면들을 떠올리시고 거기서 Stepper Motor가 적용된다면 어떤 느낌으로 회로도를 구성하고 코딩 하면 좋을 지 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] Stepper Motor 원하는 각도 회전(1)

IOT/아두이노|2019. 5. 2. 09:00

[아두이노] Stepper Motor 원하는 각도 회전(1)



지난 시간에 Stepper Motor를 간단히 360도 회전 실험을 했습니다. 이제는 Stepper Motor로 자유자재로 회전을 시켜 봐야 겠지요. 그럼 원하는 각도로 회전 시키는 방법을 알아보도록 합시다.


1. Stepper Motor 회전의 원리


회전을 제어하는 Motor는 대표적으로 두 종류가 있습니다. Servo Motor와 Stepper Motor 입니다. 둘은 비슷하게 회전하지만 실제 회전 명령을 내릴 때는 약간의 차이가 있습니다. Servo Motor의 경우 0~180도 사이 각으로 회전을 하게 됩니다. 여기서 90도 회전 할 경우 servo.write(90도) 이라고 표현하면 90도 만큼 회전 됩니다. 그리고 90도 위치에서 다시 120도 위치로 갈려면 servo.write(120도) 이라고 표현하면 됩니다. 즉, 원하는 각도로 가고 싶으면 해당 각도값을 넣으면 해당된 위치로 Servo Motor가 회전하게 됩니다.

하지만 Stepper Motor의 경우 좀 다릅니다. 360도 회전 시킬 수 있는 Motor 입니다. 여기서, 90도 회전시 stepper.step(90도스텝수) 표현하면 90도 만큼 회전 됩니다. 그런데 90도 위치에서 120도 위치로 갈려면 stepper.step(120도스텝수) 이라고 하면 안됩니다. stepper.step(120도스템수)이라고 하면 현재 90도 위치이지만 그 시점에서 새롭게 120도 만큼 회전을 하여 210도를 위치로 회전 됩니다. 즉, 회전이 끝난 지점이 새로운 회전이 시작되는 지점이니깐 90도 회전 후 120도 위치로 회전 될려면 Stepper Motor는 30도 회전을 시켜야 합니다. 이점을 생각하시고 코딩을 하셔야 합니다. 즉, 매번 회전 명령을 내리는 곳이 시작점이 되는 거라고 생각하시면 됩니다.

Servo Motor와 Stepper Motor의 회전는 이점을 생각하고 코딩하면 됩니다.

2. Stepper Motor 회로도



  • 준비물 : 5V 스템모터, ULN2003 모터드라이버, 아두이노우노
  • 내용 : 8,9,10,11핀을 순서대로 IN1, IN2, IN3, IN4에 연결하고 스템모터와 UNL2003 모터쉴드에 연결하시오.


지난 시간과 동일한 회로도를 사용하였습니다.


3. 코딩



함수

#include <Stepper.h>
  • Stepper stepper(STEPS, IN1, IN2, IN3, IN4) : 사용하는 Stepper Motor 스템수, 각 4핀을 세팅.
  • stepper.setSpeed(값) : Stepper Motor의 속도 설정.
  • stepper.step(스텝수) : 스템수로 회전 각을 표현 한다.

시리얼 통신

  • Serial.begin(9600) : 시리얼 통신 시작(9600 통신속도)
  • Serial.println(값) : 시리얼모니터 출력
  • Serial.available() : 시리얼통신으로 데이터가 들어놨는지 상태 확인
  • Serial.parseInt() : Int형으로 데이터를 읽음

[지난 시간 소스]

#include <Stepper.h>

#define STEPS 2048

Stepper stepper(STEPS, 8, 10, 9, 11);

void setup() {
  stepper.setSpeed(12);
}

void loop() {
  stepper.step(STEPS);
  delay(1000);
  stepper.step(-STEPS);
  delay(1000);
}

위 소스를 가지고 수정을 합시다.

우선, 아두이노 IDE 시리얼모니터에서 입력으로 회전각을 입력한다고 가정하면 아래와 같이 회전 각을 int형으로 읽어서 val변수에 회전각을 저장하게 표현 했습니다. 참고로 정수로 입력하는 방식으로 정수로 읽게 parseInt()함수로 표현 했고요.

if(Serial.available()) {
    int val=Serial.parseInt();
}

이제 val이라는 변수는 회전각도 값이 들어 있으니깐 이 각도를 실제 Stepper Motor의 회전 스템수로 변환 시켜야 겠죠. 스템수가 회전각이니깐요. 가독성으로 각도로 입력을 했습니다. 각도에 대한 스템수를 구하는 식이 필요 하겠죠. 예로 180도라고 입력을 하면 180도에 대한 스템수 1024값을 구해야 합니다.

그러기 위해서는 다음과 같이 map()함수를 이용합니다.

val=map(val,0,360,0,2048);

map() 함수에 입력각 val에 대한 입력 범위 0~360에서 출력 0~2048의 스템수를 세팅하면 회적 각도에 따라 스템수를 만들어 낼 수 있습니다. val이 180이면 스템수는 1023이 나오고 만약 -180도면 -1023 스템수가 나오게 됩니다. 이렇게 해서 각도에 대한 스템수를 만들어 냈습니다.

회전은,

stepper.step(val);

마무리로 step() 명령으로 실제 Stepper Motor를 회전을 시켜 원하는 각도에 제어할 수 있게 됩니다.

종합해서 코딩하면,

#include <Stepper.h>

const int STEPS = 2048;
Stepper stepper(STEPS, 8,10,9,11);

void setup()
{
  stepper.setSpeed(14);
  Serial.begin(9600);
}

void loop()
{
   if(Serial.available()) {
    int val=Serial.parseInt(); //회전각 int형으로 읽기
    
    val=map(val,0,360,0,2048); //회전각 스템 수
    stepper.step(val);
    Serial.println(val);
    delay(10);
  }
}

아두이노 IDE 시리얼모니터에서 입력한 각도에 따라 원하는 각도로 Stepper Motor를 회전을 시킬 수 있게 되었습니다.

4. 결과


아두이노 IDE 시리얼모니터에서 각도를 입력하면 Stepper Motor가 그 각도에 맞에 회전을 하는 영상입니다.


마무리


아두이노 IED 시리얼 모니터에서 입력한 회적각을 map()함수로 회전 스템수로 구하고 step()함수로 실제 Stepper Motor를 회전 키는 로직을 완성 했습니다. 시리얼 통신으로 회전을 제어 할 수 있게 되었으니깐 이걸로 블루투스 통신으로 하면 스마트폰으로 쉽게 Stepper Motor를 회전 시킬 수 있겠죠. 아니면 processing 으로 이미지로 버턴을 만들어서 Stepper Motor를 회전 시킬 수 도 있습니다. 그것도 아니면, 입력을 조이스틱이나 가변저항 같은 것들로 외부의 다른 Sensor를 이용해서 회전을 시킬 수 도 있습니다. 선택은 여러분의 상상력에 따라 달라집니다.

추가로, Bluetooth를 이용해서 스마트폰으로 회전을 시켰는데 오늘 전부 다 올리려고 하니 좀 내용이 길어질 것 같아서 나눠서 내일 post에 올리도록 하겠습니다.

여러분들은 Stepper Motor를 가지고 어떻게 회전을 할지 상상력을 펼쳐 보세요.


댓글()

[아두이노] Stepper Motor 라이브러리로 제어

IOT/아두이노|2019. 5. 1. 09:00

[아두이노] Stepper Motor 라이브러리로 제어



오늘은 복잡하게 Stepper Motor의 4핀을 직접 제어할 필요 없이 Stepper Motor 라이브러리를 사용하여 쉽게 제어하는 실험을 하겠습니다.


1. Stepper Motor 회로도



  • 준비물 : 5V 스템모터, ULN2003 모터드라이버, 아두이노우노
  • 내용 : 8,9,10,11핀을 순서대로 IN1, IN2, IN3, IN4에 연결하고 스템모터와 UNL2003 모터쉴드에 연결하시오.


Stepper Motor 라이브러리를 실험하기 위해 따로 새롭게 만들 필요가 없기에 그냥 지난 시간에 만든 회로도를 그대로 사용하겠습니다.


2. 코딩



함수

#include <Stepper.h>
  • Stepper stepper(STEPS, IN1, IN2, IN3, IN4) : 사용하는 Stepper Motor 스템수, 각 4핀을 세팅.
  • stepper.setSpeed(값) : Stepper Motor의 속도 설정.
  • stepper.step(스텝수) : 스템수로 회전 각을 표현 한다.

아두이노 IDE Stepper 예제에 보시면 MotorKnob 예제가 있습니다. 원래 동작은 A0에 입력되는 아날로그 신호에 의한 회전인데 아마도 조이스틱과 가변저항으로 조정한 값을 Stepper Motor의 회전각을 만드는 것 같더군요. 오늘 실험은 이걸 하기 위한게 아니라 간단히 회전을 시킬 수 있는지에 대해 테스트 실험이기 때문에 수정을 하겠습니다.

[소스] : MotorKnob 예제입니다.

#include <Stepper.h>

#define STEPS 100
Stepper stepper(STEPS, 8, 9, 10, 11);
int previous = 0;

void setup() {
  stepper.setSpeed(30);
}

void loop() {
  int val = analogRead(0);
  stepper.step(val - previous);
  previous = val;
}

위 소스를 가지고 수정을 합시다.

우선,

#define STEPS 100

Stepper Motor의 Step의 총수입니다. 즉, 360도 회전에 Step 수라고 생각하시면 됩니다. 이부분은 여러분들이 변경해야 합니다. 자신이 사용하는 Stepper Motor의 종류에 따라서 계산해야 합니다.



STEPS = (360/step angle)* Gear ratio


예) [ 28BYJ-48 5V DC Stepper Motor]

  • Number of Phase : 4

  • Speed Variation Ratio : 1/64

  • Stride Angle : 5.625° /64

  • STEPS = (360/5.625)*64 = 4096


실제로 4096으로 입력하면 제 모터에서는 2바퀴를 회전하더군요. 2048로 STEPS을 잡으니깐 360도 회전을 할 수 있었습니다.

다음으로 핀 연결인데 위 회로도 대로 연결해서 돌리면 사실 돌아가지 않아서 처음 공부 할 당시 애를 먹었던 부분입니다. 처음에 삽질 했는데 핀 위치가 문제였더군요. 위 회로도로 연결했을 때 핀위치는 바뀌어야 합니다.

Stepper stepper(STEPS, 8, 9, 10, 11);

변경,

Stepper stepper(STEPS, IN1, IN3, IN2, IN4);
Stepper stepper(STEPS, 8, 10, 9, 11);

이렇게 설정하여 STEPS로 회전 시키니깐 시계방향으로 360도 회전 하였네요. -SEPS로 하니깐 반시계방향으로 360도 회전이 되었고요.

그 다음, stepper Motor의 회전 속도를 steup()함수에서 설정합니다. 하지만 이 speed값은 STEPS의 수와 관계가 있습니다. 만약 4096으로 잡고 돌릴 경우에는 5~7정도의 speed를 잡아야 정상적으로 회전이 일어나고 10정도 입력하면 회전을 하지 않습니다. 2048의 경우는 10~14사이가 정상적으로 회전을 하더군요.

stepper.setSpeed(12);

실제 회전 명령은 step()함수로 step수는 회전각입니다.

stepper.step(step수);

종합해서 수정하면, 정방향으로 360도 회전 후 역방향으로 360도 회전

#include <Stepper.h>

#define STEPS 2048

Stepper stepper(STEPS, 8, 10, 9, 11);

void setup() {
  stepper.setSpeed(12);
}

void loop() {
  stepper.step(STEPS);
  delay(1000);
  stepper.step(-STEPS);
  delay(1000);
}

4. 결과


회전은 깔끔하게 되긴 했는데 오차각이 좀 생기네요. Stepper Motor 싼거라 분해능력이 떨어져서 각이 약간 오차가 발생해서 정교한 각도 제어는 제가 실험한 Stepper Motor는 다소 무리가 있네요.


마무리


복잡하게 생각을 하지 않아도 Stepper Motor라이브러리로 쉽게 회전을 시킬 수 있겠죠. 코딩량도 대폭 줄어 들고 간단히 세개의 함수의 의미만 이해하면 Stepper Motor를 회전 시킬 수 있습니다.

Stepper stepper(STEPS, 8, 10, 9, 11);
stepper.setSpeed(12);
stepper.step(STEPS);

Stepper 객체변수 선언하고 Stepper 객체변수의 setSpeed()함수의 회전속도와 step()회전 스템수로 각도f를 회전 하게 됩니다. 이 세개의 함수만 이해하시면 쉽게 제어 할 수 있게 됩니다. 그런데 사실 쉽지는 않습니다. STEPS의 수를 계산하기가 약간 어려울 수 있습니다. Stepper Motor의 부품 사양을 보고 계산해서 구해야 하기 때문에 이부분이 어려울 수 있지만 이부분만 제대로 지정해 주시면 그 다음 부분들은 어렵지 않을 꺼에요.

참고로, 다른 Stepper Motor를 사용하실 때에는 해당 Stepper Motor 라이브러리를 검색하시셔 라이블러리에 추가해서 사용하시면 됩니다. 혹시 라이브러리가 없는데 그냥 따라서 include만 시킨다고 되는게 아니니깐요. 자신이 사용하는 부품명으로 우선 검색하시고 있으면 그걸 사용하세요. 없다면 공용 Stepper Motor 라이브러리를 사용하시고요.

마지막으로, 여러분들은 360도 회전을 할 수 있다면 어떤 것을 해보고 싶은지 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] Stepper Motor 제어

IOT/아두이노|2019. 4. 30. 09:00

[아두이노] Stepper Motor 제어



오늘은 Stepper Motor를 다뤄보려고 합니다. Motor편은 Servo Motor 이후 오랫만이죠. Servo Motor은 아두이노에서 바로 제어가 가능하기 때문에 따로 준비사항이 없었지만 Stepper Motor나 DC Motor는 모터 쉴드가 필요합니다. 아두이노에서 직접 Motor에 연결해서는 안됩니다. 직접 연결한다고 해서 작동을 안하는 것은 아니지만 아두이노에 문제가 생길 수 있기 때문에 직접 제어를 피해야 합니다. 그 이유는 Motor는 많은 전류를 필요하기 때문에 아두이노에 전류를 공급할 때 아두이노에서 일시적으로 전류가 불안정한 상태에 빠져 숏다운도 될 수 있습니다. 그리고 Motor의 역전류 현상에서 아두이노에 역전류가 흐르게 되면 아두이노는 치명적 손상을 입히게 됩니다. 그래서, Motor의 경우는 아두이노에 직접 Motor와 연결하지 않습니다. 그 사이에 모터 쉴드가 필요하고 모터 쉴드를 통해서 Motor를 제어하게 됩니다.

오늘 배우게 될 Stepper Motor는 참 재있는 부품입니다. Servo Motor와 유사하게 각도를 제어한 부품입니다. Servo Motor는 일반적으로 360도 회전이 안됩니다. 변형시키거나 특수 Motor의 경우는 회전이 가능하지만 일반적으로 일정 사이각 180도로 회전이 제한이 됩니다. 하지만 Stepper Motor는 360도 회전 뿐 아니라 각도를 정교하게 회전 시킬 수 있어 큰 장점을 지닌 Motor입니다.

이제 본격적으로 Stepper Motor에 대해서 살펴보도록 하겠습니다.


1. 5V 스템모터 + ULN2003 모터 드라이버



[ Fritzing 부품 그림 ]


Stepper Motor는 모터 내부의 고정자의 극 수에 따라서 1상, 2상, 3상, 4상, 5상, 6상 등 여러 종류로 나뉩니다.

그리고, 회로방식에서 Unipolar Steppers, Bipolar Steppers으로 나뉩니다. 아래 아두이노 공식 홈페이지의 튜토리얼에 자세히 나와 있으니깐 읽어주세요.



제 실험에서 Stepper Motor를 ULN 2003 모터 드라이브로 제어를 하게 됩니다.

Stepper Motor의 자세한 설명은 사실 포스트에 전체적인 내용을 쓰기에는 그림작업이 너무 힘들고 글로써 설명하자니 그림 없이 의미 전달하기에는 가독성이 너무 떨어지고 해서 괜찮은 글들을 소개하는 수준으로 Stepper Motor의 기본 개념 설명을 대신하고자 합니다. 사실 이태훈님의 블로그보다 더 쉽게 설명을 할 자신이 없어서 아래 참고할만한 사이트들을 링크 걸어놓습니다.


[출처]


참고로, pdf 파일로 만들어 놓은 세번째 링크 주소에서 유니플러 "1 상 여자 동작" 이 부분을 특히 잘 봐주시기 바랍니다. 이부분을 사용하여 Stepper Motor를 제어를 실험할 예정입니다. 1 step에 하나의 상만 전류가 공급되는 방식인데 이걸로 스템모터를 라이브러리 없이 모터를 제어할 수 있습니다.

1 step => A상(5V), B상(0V), C상(0V), D상(0)
2 step => A상(0V), B상(5V), C상(0V), D상(0)
3 step => A상(0V), B상(0V), C상(5V), D상(0)
4 step => A상(0V), B상(0V), C상(0V), D상(5V)

예) 1 step 일 경우 :

  digitalWrite(stepPin[0],HIGH);
  digitalWrite(stepPin[1],LOW);
  digitalWrite(stepPin[2],LOW);
  digitalWrite(stepPin[3],LOW);
  delay(10);

이렇게 계속 반복을 하고 각도를 회전하게 됩니다 위 step 순서로 전류가 공급되었을 때 이 방향을 정방향이라고 하면 역방향은 위 과정을 역순으로 진행하면 역방향이 되겠죠. 링크된 pdf 파일에 있는 곳에서 그림으로 보시면 대충 어떤식으로 진행되는지만 파악해 두세요. 이걸 코딩으로 표현한다면 어떻게 할지도 여러분들이 공곰히 생각해보세요.

힘든 분들은 이부분을 그냥 잊어주세요. 편하게 라이브러리를 처음에 사용하시는 것이 좋겠죠.

스템 모터 쉴드


위 그림을 보시면 대충 위치는 파악 하실 수 있겠죠. 참고로 Stepper Motor선 연결은 연결부분이 구별되어 있어서 개별핀의 위치는 신경 안쓰셔도 됩니다. 회로도를 그릴 때 만 연결 핀 위치를 명확하게 표현 해야하지만요. 참고로 아두이노에서 IN1에 전류가 공급되면 입력 핀에 신호가 온 것을 해당 LED에 불이 들어오게 하여 입력 신호 상태를 알 수 있는 모터 드라이브네요. 실제로 구매하시면 전원 담당 부분은 +, -가 표기가 제대로 안되어 있으니깐 +, -위치는 암기해 주세요. 나머지 선은 순서대로 연결만 하면 됩니다.

자세히 세부적인 핀 연결은 아래 그림을 잘 확인하시면 됩니다. 연결 선은 Color Name으로 표시 되어 있기 때문에 맞춰서 연결하시면 됩니다. 이 동작은 위에 링크 걸린 곳에 가시면 다른분이 자세한 설명이 있으니깐 깊게 공부하실 분들은 가셔서 필독하시면 됩니다.


제가 생각하기에는 처음에는 우선 스템 모터를 회전시키는 동작에만 초점을 두었으면 합니다. 뭔가 실제로 돌아가는 걸 보고 나서 스템 모터의 내부 원리에 대해서 이해하시는게 더 좋을 듯 싶네요. 나중에 이걸로 다양한 표현을 하다가 좀 더 깊게 공부하고 싶은 욕구가 생길 때 정석으로 공부하시고 지금은 그냥 모터를 회전시킬 수 있는 것에만 관심을 가지시면 됩니다. 스템 모터 라이브러리를 직접 여러분들이 만들 필요가 없으니깐요. 우리는 단지 이 부품을 가지고 회전만 시킬 수 있는 능력을 갖추시면 됩니다. 그리고 회전을 시켰을때 이것을 어디에 써먹을지에 좀 더 초점을 두었으면 합니다.

2. Stepper Motor 회로도


  • 준비물 : 5V 스템모터, ULN2003 모터드라이버, 아두이노우노
  • 내용 : 8,9,10,11핀을 순서대로 IN1, IN2, IN3, IN4에 연결하고 스템모터와 UNL2003 모터쉴드에 연결하시오.

여기서 전원부분은 아두이노에서 빼냈습니다. 참고로 전원은 아두이노보다는 따로 외부 전원을 사용하시는 것이 좋습니다. 귀찮아서 실제로도 아두이노에 연결해서 사용했지만 Stepper Motor를 여러개 연결 할 경우 아두이노에 문제가 생길 수도 있습니다.


3. 코딩


  • 내용 : stepper 라이브러리 없이 1상 여자 방식으로 회전 시켜보자.

함수

pinMode(사용핀,사용모드) : 사용핀을 INPUT/OUTPUT 모드를 설정
digitalWrite(사용핀,출력상태) : 사용핀을 HIGH(5V) or LOW(0V) 설정
delay(시간값) : 시간값만큼 대기




1상 여자 방식은 전류의 흐름을 아래 그래프와 같습니다.


이걸 표로 살펴보면,


위 표처럼 4개의 핀에 전류를 순서대로 공급하면 됩니다.

회로도에서 핀 8(A), 9(B), 10(C), 11(D)의 핀을 전류 공급 순서를 step 순서대로 순차적으로 공급하면 Stepper Motor가 회전을 하게 됩니다.

1 step => A상(5V), B상(0V), C상(0V), D상(0)
2 step => A상(0V), B상(5V), C상(0V), D상(0)
3 step => A상(0V), B상(0V), C상(5V), D상(0)
4 step => A상(0V), B상(0V), C상(0V), D상(5V)

1 Step : 1,0,0,0 으로 사용자 정의 함수를 하나 phasesate()함수를 하나 만들어 봅시다.

void phasesate(int a, int b, int c, int d, int delayval){
  digitalWrite(stepPin[0],a);
  digitalWrite(stepPin[1],b);
  digitalWrite(stepPin[2],c);
  digitalWrite(stepPin[3],d);
  delay(delayval);
}

이렇게 함수를 하나 정의해 놓으면 이 함수를 호출함으로서 아래와 같이 간단히 표현할 수 있습니다.

phasesate(1,0,0,0,10);

phasesate(1번핀,2번핀,3번핀,4번핀,속도)로 이렇게 표현이 됩니다.

패턴을 하나의 함수로 묶으면,

void stepmovea(){
  phasesate(1,0,0,0,10);
  phasesate(0,1,0,0,10);
  phasesate(0,0,1,0,10);
  phasesate(0,0,0,1,10);
}

이제 회전을 시켜볼까요.

void loop() {
  for(int i=0;i<500;i++){
    stepmovea();
  }
}

약 500정도에 360도 근처정도의 회전을 시키게 됩니다. 정확히 360도 회전을 하지 않습니다.

역회전을 한다면, stepmovea() 패턴 함수를 역순으로 진행하면 됩니다.

void stepmoveb(){
  phasesate(0,0,0,1,10);
  phasesate(0,0,1,0,10);
  phasesate(0,1,0,0,10);
  phasesate(1,0,0,0,10);
}

이렇게 하면 역순으로 회전이 되겠죠.

코드를 종합해 보면.

const int stepPin[4] = {8,9,10,11};

void setup() {

  for(int i=0;i<4;i++){
    pinMode(stepPin[i],OUTPUT);
  }
}

void loop() {
 
  for(int i=0;i<500;i++){
    stepmovea();
  }
  for(int i=0;i<500;i++){
    stepmoveb();
  }
}
void phasesate(int a, int b, int c, int d, int delayval){
  digitalWrite(stepPin[0],a);
  digitalWrite(stepPin[1],b);
  digitalWrite(stepPin[2],c);
  digitalWrite(stepPin[3],d);
  delay(delayval);
}

void stepmovea(){
  phasesate(1,0,0,0,10);
  phasesate(0,1,0,0,10);
  phasesate(0,0,1,0,10);
  phasesate(0,0,0,1,10);
}

void stepmoveb(){
  phasesate(0,0,0,1,10);
  phasesate(0,0,1,0,10);
  phasesate(0,1,0,0,10);
  phasesate(1,0,0,0,10);
}

4. 결과


회전 속도를 10으로 해서 그런지 좀 느리게 회전을 하네요. 그리고 500번의 루프를 돌았는데 약 360도 정방향으로 회전 했다가 역방향으로 회전하고 이렇게 반복적으로 회전을 수행한 결과입니다.

마무리


오늘은 Stepper 라이브러리 없이 회전을 직접 시도 했습니다. 회전시 문제점은 정교한 회전을 하기 위해서는 Stepper Motor의 사양과 delay(시간)값을 수학적으로 계산해야 합니다. 이런 복잡한 부분을 직접 코딩하는 것은 귀찮은 일이죠. Stepper Motor의 종류에 따라서 접근 방식과 계산이 달라지기 때문에 시간적으로 낭비입니다. 그렇기 때문에 우리는 편하게 Stepper 라이브러리를 사용해야 합니다. Stepper Motor로 뭘 만들지 상상해야지 Stepper Motor를 직접 라이브러리를 만드는데 시간을 낭비하면 안되겠죠.

Stepper Motor가 어떻게 회전을 했는지만 의미만 이해하시고 이론적인 부분은 위에 링크로 소개한 게시물들로 가셔서 이론을 배우세요.


댓글()