산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

모든 DC 모터를 맞춤형 360° 서보로 변환 – 단계별 가이드

이 튜토리얼에서는 DC 모터를 다양한 기능을 갖춘 독립형 맞춤형 서보 모터로 전환하는 방법을 배웁니다. 180도 또는 270도의 제한된 모션을 갖는 일반 서보와 달리 이 서보는 360도의 무제한 범위를 가지며 게다가 회전 범위를 필요한 값으로 조정할 수 있습니다.

제 생각엔 꽤 편리할 것 같고, 게다가 서보의 중심점도 조정할 수 있습니다. 그래서 중심점과 회전 범위를 동시에 조정할 수 있습니다.

다음 비디오를 보거나 아래에 작성된 튜토리얼을 읽어보실 수 있습니다.

또 다른 특징은 감도를 조정하거나 서보가 입력에 얼마나 빨리 반응하는지를 조정할 수 있다는 것입니다. 입력에 관해 말하면 세 가지 다른 입력 모드가 있을 수 있습니다.

아날로그 전압 입력이나 전위차계를 사용하여 서보를 제어할 수 있으며, RC 송신기로 서보를 제어할 수 있을 뿐만 아니라 PC나 노트북의 직렬 모니터를 통해 각도 값을 입력하여 직렬 포트를 통해 서보를 제어할 수도 있습니다.

동시에 직렬 모니터를 통해 값을 입력하여 서보를 제어하고 RC 송신기를 사용하여 서보를 수동으로 이동할 수도 있습니다. 서보 모터는 항상 현재 위치를 알고 있으며 직렬 모니터에서 이를 볼 수 있습니다. 

이 서보 모터 기능 목록의 맨 위에는 연속 회전 모드가 있습니다. 좋아요. 이 연속 회전 모드에서도 서보 모터 위치를 제어하고 추적할 수 있습니다. 서보 모터 샤프트가 무한한 회전 수로 어떤 위치로든 이동하도록 설정할 수 있습니다.  

이 모든 것은 이 서보 모터에 사용되는 12비트 인코더, AS5600 자기 회전 위치 센서 및 DC 모터 구동을 위해 구현된 PID 제어 덕분에 가능합니다.

저는 자체 마이크로컨트롤러와 모든 DC 모터를 독립형 서보 모터로 쉽게 전환할 수 있는 모든 것을 포함하는 맞춤형 서보 모터 컨트롤러 보드를 만들었습니다.

보드를 출력 샤프트(샤프트의 특정 자석 포함) 중앙에 배치하고, 최대 3.5A 정격 전류로 모든 크기의 DC 모터를 연결하고, 전체 시스템에 12V 전원을 공급하기만 하면 됩니다. 그러면 이러한 모든 기능을 갖춘 일반 DC 모터의 서보 모터가 생성됩니다.

이제 이 맞춤형 서보 모터를 만드는 전체 과정을 안내해 드리겠습니다. 따라서 여러분도 직접 만들 수 있습니다. 서보 모터, 폐쇄 루프 컨트롤러, PID 컨트롤러의 작동 원리, 이를 위한 맞춤형 PCB 및 기어박스 설계 방법, 그리고 그 이면의 코드에 대해 설명하겠습니다.

서보 모터 작동 원리

서보 모터의 작동 원리를 설명하기 위해 일반적인 RC 서보 모터를 분해하여 내부 구성품을 살펴보겠습니다.

작은 DC 모터, 컨트롤러 보드, 전위차계, 3선 연결, 전원용 전선 2개, 입력 신호용 전선 1개가 있음을 알 수 있습니다. 또한 DC 모터의 속도를 줄이고 토크를 높이기 위한 일부 기어가 있습니다. 

이는 대부분의 RC 또는 취미용 서보 모터의 일반적인 설정입니다. 전위차계는 DC 모터의 출력축에 부착되어 위치 센서 역할을 하며 서보 모터 축의 현재 위치를 컨트롤러에 알려줍니다. 컨트롤러 보드는 입력 신호(원하는 위치)와 전위차계에서 피드백으로 얻은 실제 위치를 기반으로 DC 모터를 제어합니다. 이는 폐쇄 루프 제어 시스템을 나타냅니다.

입력 신호 또는 원하는 위치는 위치 피드백 센서에서 얻은 모터의 실제 위치와 비교됩니다. 오류라고 불리는 발생하는 차이는 모터가 원하는 위치에 도달할 때까지 움직이도록 명령하는 컨트롤러에서 처리됩니다.

맞춤형 서보 모터를 만드는 방법

따라서 일반적인 RC 서보가 사용하는 것보다 더 큰 DC 모터로 자체 서보 모터를 구축하려는 경우 동일한 폐쇄 루프 제어 시스템을 구현할 수 있습니다.

어떤 식으로든 출력 샤프트에 부착된 위치 센서와 DC 모터를 구동하기 위한 마이크로컨트롤러만 있으면 됩니다.  

이제 위치 센서의 경우 가장 간단한 해결책은 RC 서보에서 본 것과 같은 간단한 전위차계를 사용하는 것입니다. 하지만 이러한 유형의 전위차계의 문제점은 회전 범위가 270도로 제한되어 있어 서보 모터의 회전 범위가 직접적으로 제한된다는 것입니다. 여러 번 회전할 수 있고 더 나은 범위와 분해능을 제공할 수 있는 다른 유형의 전위차계도 있지만 여전히 회전이 제한되어 있습니다.

무제한 회전 범위를 갖는 서보 모터가 필요한 경우 엔코더를 사용해야 합니다. 인코더는 무제한 회전으로 샤프트의 각도 위치를 추적할 수 있는 전기 기계 장치입니다. 증분형 또는 절대형 인코더와 같은 다양한 유형의 인코더가 있으며 감지 기술에 따라 광학식, 자기식 또는 용량성 인코더가 있습니다. 물론 각각의 장점과 단점이 있습니다.

AS5600 인코더 – 자기 회전 위치 센서

나는 자기 인코더 또는 AS5600 자기 회전 위치 센서를 사용하기로 결정했습니다. 그 이유는 매우 콤팩트하고 높은 정밀도나 분해능을 제공하는 인코더를 구현하기 쉽기 때문입니다. 이 마이크로칩이 얼마나 작은지 살펴보세요.

자기장의 방향 변화를 감지할 수 있는 홀 효과 센서가 내장되어 있습니다. 그래서 모터 출력축에 자석을 부착하고 마이크로칩과 0.5~3mm 정도의 거리를 두고 위치시키기만 하면 됩니다.

이제 모터 샤프트와 자석이 회전하면 홀 효과 센서가 자기장 방향의 변화를 포착합니다. 내장된 12비트 A/D 변환기의 도움으로 AS5600 센서는 회전당 4096개의 위치 또는 360도 회전을 출력할 수 있습니다.

즉, 0.0878도 정도의 작은 각도 위치 변화도 감지할 수 있습니다. 이는 매우 인상적이며 매우 저렴하고 쉽게 구할 수 있다는 점을 고려하면 맞춤형 서보 모터를 위한 올바른 선택입니다. 

좋습니다. 그러면 마이크로컨트롤러와 DC 모터용 드라이버가 더 필요합니다. 저는 최대 3.5암페어의 전류를 처리할 수 있는 DRV8871 DC 모터 드라이버와 Atmega328 마이크로컨트롤러를 선택했습니다.

저는 DIP 버전보다 훨씬 컴팩트한 표면 실장 버전을 선택했고, 제 목표는 서보가 독립형 장치로 작동할 수 있도록 모든 것을 포함할 수 있는 맞춤형 PCB를 최대한 작게 만드는 것이었습니다.

맞춤형 서보 모터 회로도

맞춤형 서보 모터의 전체 회로도는 다음과 같습니다.

아래 링크에서 이 프로젝트에 필요한 구성요소를 얻을 수 있습니다:

공개:제휴 링크입니다. Amazon Associate로서 저는 적격 구매를 통해 수입을 얻습니다.

따라서 우리는 16Mhz 발진기, 소수의 커패시터 및 저항기를 포함하는 권장 최소 회로와 함께 Atmega328 마이크로 컨트롤러를 보유하고 있습니다.

5V가 필요한 마이크로컨트롤러와 기타 구성 요소에 전원을 공급하기 위해 우리는 AMS1117 전압 조정기를 사용하고 있는데, 이는 12V 전원 입력을 5V로 떨어뜨립니다.

다음은 IC2 통신을 위한 2개의 커패시터와 2개의 풀업 저항기를 포함하는 권장 회로를 갖춘 AS5600 위치 센서입니다.

DRV8871 DC 모터 드라이버에는 전류 제한을 위한 저항기 1개와 디커플링 커패시터 2개가 필요합니다. 그런 다음 마이크로 컨트롤러의 아날로그 입력에 연결된 두 개의 전위차계가 있습니다. 하나는 회전 범위를 조정하고 다른 하나는 서보의 감도를 조정합니다. 푸시 버튼은 서보의 중심점을 설정하는 데 사용되며 양방향 딥 스위치는 서보의 작동 모드를 선택하는 데 사용됩니다. 서보 입력용 핀 헤더(아날로그 전압 입력 또는 RC 수신기의 디지털 PWM 입력)와 5V 및 접지 핀이 있습니다. SPI 프로토콜과 직렬 포트를 통해 마이크로컨트롤러를 프로그래밍하기 위한 핀 헤더도 있습니다. 

다음은 이 회로와 해당 작업 흐름을 요약한 것입니다. 입력 또는 원하는 각도 위치는 이 두 핀을 통해 수신되며 전위차계에서 나오는 아날로그 전압이거나 RC 수신기에서 나오는 디지털 PWM 신호일 수 있습니다. 입력은 마이크로컨트롤러로 들어가 인코더나 AS5600 위치 센서에 의해 감지된 실제 각도 위치와 비교됩니다. 이 센서는 IC2 프로토콜을 통해 마이크로컨트롤러와 통신합니다.

그런 다음 마이크로 컨트롤러는 수학을 수행하고 오류를 계산하며 이에 따라 원하는 위치에 도달할 때까지 DC 모터를 구동하는 DRV8871 드라이버에 PWM 신호를 보냅니다. 

전체 회로는 12V로 전원이 공급되며 AS1117 전압 조정기는 마이크로 컨트롤러와 기타 구성 요소에 적절하게 5V를 제공합니다.

PCB 디자인 

회로도대로 PCB를 최대한 작게 디자인하려고 했더니 40x40mm로 나왔어요.

서보의 출력 샤프트에 쉽게 장착하고 정렬할 수 있도록 인코더를 PCB의 아래쪽, 정확히 중앙 지점에 배치합니다.

다른 모든 구성 요소는 인코더 및 출력 샤프트를 방해하지 않도록 반대쪽에 배치됩니다.

PCBWay에서 PCB를 주문했습니다. 여기에서는 간단히 Gerber 파일을 업로드하고 PCB의 속성을 선택한 후 합리적인 가격으로 주문할 수 있습니다.

저는 PCB를 4개의 레이어로 설계했는데, 중간 레이어는 GND용이므로 가격이 약간 올라갑니다. 흰색으로 선택한 PCB 색상을 제외하고 기본 속성을 변경하지 않았으며, 적용 가능한 경우 추가 비용 없이 표면 마감을 Immersion Gold로 변경하는 것을 허용합니다.

PCBWay 프로젝트 공유 커뮤니티에서 Gerber를 찾아 다운로드할 수도 있으며, 이를 통해 PCB를 직접 주문할 수도 있습니다.

그럼에도 불구하고 며칠 후 PCB가 도착했습니다. PCB의 품질이 훌륭하고 모든 것이 디자인과 동일하며 침지 금 표면 마감 처리되어 있습니다.

좋습니다. 이제 부품을 납땜하는 작업을 진행할 수 있습니다. 저는 이 표시 LED, 커패시터, 저항기 같은 작은 구성 요소부터 시작했습니다.

실제로 이 작은 SMD 부품을 납땜하는 것은 이번이 처음이었는데, 정말 정말 서툴렀습니다. 

가장 어려웠던 점은 핀이 매우 작고 서로 매우 가깝기 때문에 Atmega328 마이크로컨트롤러를 납땜하는 것이었지만 어떻게든 해냈습니다.

AS5600 인코더 마이크로칩은 딥 스위치, 전위차계, 터미널 블록, 핀 헤더와 같은 더 큰 스루홀 구성요소뿐만 아니라 PCB 뒷면에도 쉽게 납땜할 수 있었습니다.

어쨌든 컨트롤러 보드의 최종 모습은 이렇습니다. 결과적으로 괜찮은 결과가 나온 것 같습니다.

이제 DC 모터와 이 컨트롤러 보드에 적합한 기어박스를 만들 차례입니다. 

맞춤형 서보 3D 모델

저는 Onshape를 사용하여 이 맞춤형 서보 모터용 기어박스를 디자인했습니다. 기어박스의 디자인은 물론 DC 모터에 따라 달라집니다. 앞서 언급했듯이 방금 만든 컨트롤러 보드와 함께 어떤 크기의 DC 모터도 사용할 수 있습니다.

여기서는 직경 37mm의 DC 모터와 50RPM을 출력하는 내장 기어박스를 사용하고 있습니다. 50RPM은 서보모터로서는 좋은 속도인데, 좀 더 낮은 토크로 토크를 얻고 싶어서 3배 감속 기어박스를 만들었습니다. 그런 목적으로 헤링본 기어를 사용했는데, 3D 프린터로 효율적이고 쉽게 만들 수 있기 때문입니다.

물론 여기서는 우리가 원하는 DC 모터와 얻고자 하는 출력 속도에 따라 기어박스 디자인을 원하는 대로 자유롭게 만들 수 있습니다. 

컨트롤러 보드를 이 기어박스 뒷면에 배치하고 출력 샤프트 중앙에 완벽하게 정렬했습니다.

DC 모터 샤프트를 출력으로 직접 사용하려는 경우 1:1 기어 세트를 사용하면 샤프트의 위치를 올바르게 추적할 수 있습니다. 또는 그러한 경우에는 벨트 시스템을 사용할 수도 있습니다. 제가 말했듯이, 우리는 기어박스를 만드는데 무한한 가능성을 가지고 있습니다. 

3D 모델 및 STL 파일 다운로드

Onshape를 사용하면 웹 브라우저에서 직접 맞춤형 서보 모터의 3D 모델을 보고 탐색할 수 있습니다. (이를 위해서는 Onshape 계정이 필요합니다. 집에서 사용할 수 있는 무료 계정을 만들 수 있습니다.)

물론 3D 모델과 부품을 3D 프린팅하는 데 필요한 STL 파일도 여기에서 다운로드할 수 있습니다.

STEP 파일:

3D 프린팅용 STL 파일:

맞춤형 서보 조립

서보 모터 조립을 시작할 수 있도록 이 빌드에 대한 3D 프린팅 부품은 다음과 같습니다.

그와 함께 M3 볼트와 나사산 인서트, 베어링도 필요합니다. 

먼저 8mm 길이의 M3 볼트 몇 개를 사용하여 DC 모터를 베이스 플레이트에 고정했습니다.

그런 다음 두 개의 기어를 제자리에 설치할 수 있습니다. 작은 기어는 DC 모터 샤프트로 직접 이동하고, 큰 기어는 서보의 출력이 됩니다. 하지만 의 출력축은 두 부분으로 구성되어 있습니다.

이 출력 샤프트 부분의 양쪽에 나사 인서트를 설치했습니다. 한쪽에는 기어를 연결하기 위해, 다른 쪽에는 서보 출력에 물건을 부착하기 위해 설치했습니다. 

또한 DC 모터 샤프트에 고정하는 데 사용할 작은 기어에 나사형 인서트를 설치했습니다. 이제 페어링된 기어를 해당 위치로 밀어 넣을 수 있습니다. 헤링본 기어이기 때문에 두 개를 동시에 제자리에 밀어 넣어야 합니다. 그렇지 않으면 하나씩 삽입하면 쌍을 이룰 수 없습니다.

그러브 나사를 사용하여 작은 기어를 DC 모터 샤프트에 고정했습니다. 기어셋이 제대로 작동하는지 확인하기 위해 DC 모터에 12V를 인가해봤습니다. 

측면 패널과 출력축용 볼베어링, 탑커버를 삽입하면 기어박스 조립을 마무리할 수 있습니다.

20mm 길이의 M3 볼트로 전체 어셈블리를 고정할 수 있도록 뒷판에 M3 스레드 인서트 몇 개를 설치했습니다. 기어박스를 다시 테스트했는데 훌륭하게 작동합니다. 뒷면에서 출력 샤프트가 어떻게 회전하는지 확인할 수 있으며 여기에 AS5600 인코더가 추적할 자석을 삽입해야 합니다.

M2 볼트와 너트를 사용하여 컨트롤러 보드를 기어박스에 고정합니다. AS5600 위치 센서는 이제 자석과 완벽하게 정렬되므로 출력 샤프트가 회전할 때 자기장의 변화를 적절하게 측정합니다.

여기서 영구자석의 자화방향이 매우 중요하다는 점에 유의하시기 바랍니다. 축 방향 또는 직경 방향으로 자화되는지 여부에 따라 자석을 해당 AS5600 IC에 수직 또는 평행하게 배치해야 합니다.

AS5600 인코더가 측정할 수 있는 올바른 자화가 없기 때문에 결국 자석의 방향을 변경했습니다.

다음으로 DC 모터에 두 개의 전선을 납땜하고 모터를 터미널 블록으로 컨트롤러에 연결했습니다. 전원은 전원 터미널 블록에 두 개의 전선을 연결했는데, 반대쪽에는 12V 전원 공급 장치를 연결하기 위한 DC 전원 커넥터가 있습니다. 이로써 맞춤형 서보 모터가 완성되었습니다.

컨트롤러 프로그래밍

이제 남은 일은 이 서보에 생명을 불어넣거나 컨트롤러를 프로그래밍하는 것입니다. 이를 위해 먼저 ATmega328p 마이크로 컨트롤러에 부트로더를 구워야 합니다. 부트로더가 없으면 마이크로 컨트롤러는 우리가 보내는 언어나 코드를 이해할 수 없습니다. 

부트로더 굽기

ATmega328p에 부트로더를 구우려면 Arduino 보드가 필요합니다. 제 경우에는 Arduino Nano 보드를 사용하겠습니다.

우리는 SPI 통신을 사용할 것이므로 Arduino 보드와 컨트롤러 보드에 적합한 SPI 핀을 연결해야 합니다.

이제 Arduino IDE를 사용하여 ArduinoISP 예제 스케치를 열고 이를 Arduino Nano 보드에 업로드해야 합니다. 이 코드를 사용하면 Arduino Nano는 이제 ATmega328 마이크로컨트롤러에 부트로더를 구울 수 있습니다. 

다음으로 도구 메뉴에서 프로그래머로서 Arduino를 ISP로 선택한 다음 Burn Bootloader를 클릭해야 합니다.

부트로더를 굽는 동안 Arduino NANO 표시등이 많이 깜박이고 이로 인해 부트로더가 성공적으로 굽는 것을 볼 수 있습니다. 

코드 업로드

이 작업이 완료되면 이제 USB-UART 인터페이스 모듈을 사용하여 컨트롤러 보드에 코드를 프로그래밍하거나 업로드할 수 있습니다.

컨트롤러 보드에는 이 회로도에 표시된 것처럼 쉽게 연결할 수 있는 전용 핀이 있습니다. 

이제 제가 만든 맞춤형 서보의 코드를 열고 컨트롤러에 업로드할 수 있습니다. 하지만 그 전에 먼저 AS5600 센서 및 PID 제어용 라이브러리를 설치해야 합니다. Arduino IDE 라이브러리 관리자를 통해 쉽게 수행할 수 있습니다. 업로드 버튼을 누르면 USB-UART 인터페이스 모듈을 통해 ATmega328 컨트롤러에 코드가 기록됩니다.

이것이 바로 맞춤형 서보 모터가 완성된 것입니다. 이제 전위차계를 연결하여 테스트할 수 있습니다. 아날로그 입력은 컨트롤러 보드의 "A" 핀이 아닌 "S" 핀으로 연결된다는 점을 참고하세요.

PCB를 설계할 때 이 두 핀을 ATmega328에 잘못 연결했습니다. 그런 다음 DIP 스위치를 통해 아날로그 입력 모드를 선택하고 서보에 전원을 공급할 수 있습니다.

이제 전위차계의 아날로그 입력을 사용하여 서보 모터 위치를 제어할 수 있습니다. DC 모터를 서보 모터로 성공적으로 전환했습니다.

소스 코드

이제 이 맞춤형 서보 모터의 코드를 살펴보겠습니다.

/*
 * Custom-built Servo Motor - Arduino Code
 * by Dejan, www.HowToMechatronics.com
 * 
 * Libraries:
 * AS5600 encoder: https://github.com/RobTillaart/AS5600
 * PID conroller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h
 */
#include "AS5600.h"
#include "Wire.h"
#include <PID_v1.h>
AS5600 as5600; // use default Wire
double Pk1 = 2; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.025;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define centerSet 7
#define inputSwitch 3
#define modeSwitch 4
int ch1Value;
int encoderValue, inputValue, pwmValue;
String inString = ""; // string to hold input
int centerAngle = 2047; // 180 degrees
int angleDifference = 0;
int angleValue = 0;
int leftLimit = 30;
int rightLimit = 4067;
int rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
int quadrantNumber = 2;
int previousQuadrantNumber = 3;
int numberOfTurns = 0;
float totalAngle = 0;
int error = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
 Serial.begin(115200);
 Serial.println(__FILE__);
 Serial.print("AS5600_LIB_VERSION: ");
 Serial.println(AS5600_LIB_VERSION);
 Wire.begin();
 pinMode(motor_IN1, OUTPUT);
 pinMode(motor_IN2, OUTPUT);
 // Activate the Arduino internal pull-up resistors
 pinMode(centerSet, INPUT_PULLUP);
 pinMode(inputSwitch, INPUT_PULLUP);
 pinMode(4, INPUT_PULLUP);
 myPID.SetMode(AUTOMATIC); // PID Setup
 myPID.SetOutputLimits(-255, 255);
 myPID.SetSampleTime(20);
}
void loop() {
 // Read encoder value - current position
 encoderValue = as5600.readAngle();
 // Continuous rotation mode
 if (digitalRead(modeSwitch) == 0) {
 // Enter desired angle for the servo to go to through the serial monitor
 while (Serial.available() > 0) {
 int inChar = Serial.read();
 if (isDigit(inChar)) {
 // convert the incoming byte to a char and add it to the string:
 inString += (char)inChar;
 }
 // if you get a newline, print the string, then the string's value:
 if (inChar == '\n') {
 Setpoint = inString.toInt(); // Setpoint - desired angle
 // clear the string for new input:
 inString = "";
 }
 }
 if (digitalRead(inputSwitch) == 0) { // Potentiometer as input
 inputValue = analogRead(A0);
 if (inputValue < 400) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue < 300) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue < 200) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue > 600) {
 Setpoint = Setpoint + 0.3;
 }
 if (inputValue > 700) {
 Setpoint = Setpoint + 0.3;
 }
 if (inputValue > 800) {
 Setpoint = Setpoint + 0.3;
 }
 }
 else if (digitalRead(inputSwitch) == 1) {
 inputValue = pulseIn(ch1, HIGH, 30000); // RC receiver as input
 if (inputValue < 1450) {
 Setpoint--;
 }
 if (inputValue < 1350) {
 Setpoint--;
 }
 if (inputValue < 1250) {
 Setpoint--;
 }
 if (inputValue < 1150) {
 Setpoint--;
 }
 if (inputValue > 1550) {
 Setpoint++;
 }
 if (inputValue > 1650) {
 Setpoint++;
 }
 if (inputValue > 1750) {
 Setpoint++;
 }
 if (inputValue > 1850) {
 Setpoint++;
 }
 }
 // Convert encoder RAW values into angle value
 angle = encoderValue * 0.087890625;
 // Quadrant 1
 if (angle >= 0 && angle <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (angle >= 90 && angle <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (angle >= 180 && angle <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (angle >= 270 && angle <= 360) {
 quadrantNumber = 4;
 }
 if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalAngle >= 0) {
 totalAngle = (numberOfTurns * 360) + angle;
 }
 else {
 totalAngle = (numberOfTurns * 360) + angle;
 }
 // Establish Input value for PID
 Input = totalAngle;
 }
 // Limited Rotation Mode
 else if (digitalRead(modeSwitch) == 1) {
 rangeAdjustment = analogRead(A1);
 leftLimit = 0 + 30 + rangeAdjustment;
 rightLimit = 4097 - 30 - rangeAdjustment;
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 inputValue = analogRead(A0);
 if (inputValue < 15) {
 inputValue = 15;
 }
 if (inputValue > 1008) {
 inputValue = 1008;
 }
 Setpoint = map(inputValue, 15, 1008, -255, 255);
 }
 else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 inputValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 Setpoint = map(inputValue, 1000, 2000, -255, 255);
 }
 // Set center angle
 if (digitalRead(centerSet) == LOW) {
 centerAngle = encoderValue;
 angleDifference = 2047 - encoderValue;
 delay(1000);
 }
 // Adjust angle value according to the center point (angleDifference)
 if (centerAngle < 2047) {
 angleValue = encoderValue + angleDifference;
 if (encoderValue < 4097 && encoderValue > (4096 - angleDifference)) {
 angleValue = encoderValue - 4097 + angleDifference;
 }
 }
 if (centerAngle > 2047) {
 angleValue = encoderValue + angleDifference;
 if (encoderValue >= 0 && encoderValue < abs(angleDifference)) {
 angleValue = encoderValue + 4097 + angleDifference;
 }
 }
 else if (centerAngle == 2047) {
 angleValue = encoderValue;
 }
 // Establish Input value for PID
 Input = map(angleValue , leftLimit, rightLimit, -255, 255);
 }
 // Adjusting sensitivity
 Pk1 = analogRead(A2) * 0.002;
 myPID.SetTunings(Pk1, Ik1, Dk1);
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1 ) {
 pwmValue = Output;
 if (pwmValue < 30 && pwmValue > 5) {
 pwmValue = pwmValue + 30;
 }
 if (pwmValue <= 5) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Move left
 else if (Output < 1 ) {
 pwmValue = abs(Output);
 if (pwmValue < 30 && pwmValue > 5) {
 pwmValue = pwmValue + 30;
 }
 if (pwmValue <= 5) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
 //Serial.print(Setpoint);
 //Serial.print("\t");
 //Serial.println(totalAngle);
}Code language: PHP (php)

코드 개요

따라서 엔코더 값이나 샤프트의 현재 위치를 읽어 루프를 시작합니다.

// Read encoder value - current position
 encoderValue = as5600.readAngle();Code language: JavaScript (javascript)

그런 다음 연속 회전 모드에 있는 경우 직렬 모니터의 값을 받아들이고 이를 PID 컨트롤러의 설정점 또는 원하는 각도로 사용합니다.

// Enter desired angle for the servo to go to through the serial monitor
 while (Serial.available() > 0) {
 int inChar = Serial.read();
 if (isDigit(inChar)) {
 // convert the incoming byte to a char and add it to the string:
 inString += (char)inChar;
 }
 // if you get a newline, print the string, then the string's value:
 if (inChar == '\n') {
 Setpoint = inString.toInt(); // Setpoint - desired angle
 // clear the string for new input:
 inString = "";
 }
 }Code language: JavaScript (javascript)

입력 모드가 전위차계로 설정된 경우 아날로그 입력을 읽고 회전 정도에 따라 설정값을 수정합니다.

if (digitalRead(inputSwitch) == 0) { // Potentiometer as input
 inputValue = analogRead(A0);
 if (inputValue < 400) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue < 300) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue < 200) {
 Setpoint = Setpoint - 0.3;
 }
 if (inputValue > 600) {
 Setpoint = Setpoint + 0.3;
 }
 if (inputValue > 700) {
 Setpoint = Setpoint + 0.3;
 }
 if (inputValue > 800) {
 Setpoint = Setpoint + 0.3;
 }
 }Code language: JavaScript (javascript)

입력이 RC 수신기인 경우 동일한 설정점 수정을 수행합니다. 

여기서는 RAW 인코더 값을 각도 값으로 변환하고 이러한 if 문을 사용하여 샤프트의 현재 위치가 어느 사분면에 있는지 추적합니다.

// Convert encoder RAW values into angle value
 angle = encoderValue * 0.087890625;
 // Quadrant 1
 if (angle >= 0 && angle <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (angle >= 90 && angle <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (angle >= 180 && angle <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (angle >= 270 && angle <= 360) {
 quadrantNumber = 4;
 }Code language: HTML, XML (xml)

이 정보를 통해 샤프트가 어떻게 회전하는지, 언제 완전히 회전하는지 추적할 수 있습니다. 전체 각도는 PID 제어기의 입력값입니다.

if (quadrantNumber != previousQuadrantNumber) {
 // Transition from 4th to 1st quadrant
 if (quadrantNumber == 1 && previousQuadrantNumber == 4) {
 numberOfTurns++;
 }
 // Transition from 1st to 4th quadrant
 if (quadrantNumber == 4 && previousQuadrantNumber == 1) {
 numberOfTurns--;
 }
 previousQuadrantNumber = quadrantNumber;
 }
 if (totalAngle >= 0) {
 totalAngle = (numberOfTurns * 360) + angle;
 }
 else {
 totalAngle = (numberOfTurns * 360) + angle;
 }
 // Establish Input value for PID
 Input = totalAngle;Code language: JavaScript (javascript)

반면에 제한된 회전 모드인 경우 먼저 회전 범위를 조정하는 데 사용되는 전위차계 값을 읽고 이에 따라 왼쪽 및 오른쪽 회전 제한을 조정합니다.

rangeAdjustment = analogRead(A1);
 leftLimit = 0 + 30 + rangeAdjustment;
 rightLimit = 4097 - 30 - rangeAdjustment;

입력 모드가 전위차계인 경우 해당 값을 PID 컨트롤러의 설정값으로 사용합니다.

if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 inputValue = analogRead(A0);
 if (inputValue < 15) {
 inputValue = 15;
 }
 if (inputValue > 1008) {
 inputValue = 1008;
 }
 Setpoint = map(inputValue, 15, 1008, -255, 255);
 }Code language: HTML, XML (xml)

입력 모드가 RC 수신기인 경우 수신기에서 들어오는 PWM 값을 읽고 해당 값을 설정점으로 사용합니다.

else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 inputValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 Setpoint = map(inputValue, 1000, 2000, -255, 255);
 }Code language: JavaScript (javascript)

다른 중심점을 설정하려면 푸시 버튼을 눌렀는지 확인하고 해당 위치를 새 중심점으로 캡처합니다.

// Set center angle
 if (digitalRead(centerSet) == LOW) {
 centerAngle = encoderValue;
 angleDifference = 2047 - encoderValue;
 delay(1000);
 }Code language: JavaScript (javascript)

이에 따르면 엔코더의 실제 판독값을 조정하고 새 중심점과 이전 중심점 사이의 각도 차이로 이를 오프셋해야 합니다. 해당 값을 PID 컨트롤러의 입력 값으로 사용합니다.

if (centerAngle > 2047) {
 angleValue = encoderValue + angleDifference;
 if (encoderValue >= 0 && encoderValue < abs(angleDifference)) {
 angleValue = encoderValue + 4097 + angleDifference;
 }
 }
 else if (centerAngle == 2047) {
 angleValue = encoderValue;
 }
 // Establish Input value for PID
 Input = map(angleValue , leftLimit, rightLimit, -255, 255);Code language: HTML, XML (xml)

다른 전위차계의 아날로그 입력을 사용하여 PID 컨트롤러의 비례 이득을 조정하고 마지막으로 PID 프로세스를 실행하여 출력 값을 얻습니다.

// Adjusting sensitivity
 Pk1 = analogRead(A2) * 0.002;
 myPID.SetTunings(Pk1, Ik1, Dk1);
 // Run PID process to get Output value
 myPID.Compute();Code language: JavaScript (javascript)

우리는 PID 컨트롤러의 출력 값에 따라 또는 인코더가 읽는 원하는 위치와 실제 위치 사이의 오류에 따라 왼쪽이나 오른쪽 또는 정지 위치에서 PWM 신호로 DC 모터를 구동하기 위해 해당 출력 값을 사용합니다.

// Move right
 if (Output > 1 ) {
 pwmValue = Output;
 if (pwmValue < 30 && pwmValue > 5) {
 pwmValue = pwmValue + 30;
 }
 if (pwmValue <= 5) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }Code language: HTML, XML (xml)

이것이 이 비디오의 전부입니다. 코드가 제대로 최적화되지 않았으며 개선의 여지가 있다는 점을 참고하세요.

또한 이 프로젝트를 다시 만들려면 문제를 해결할 준비가 되어 있어야 합니다. 특히 작은 SMD 부품을 납땜할 때 잘못될 수 있는 일이 많이 있습니다.

나는 첫 번째 시도부터 이 서보를 작동시키지 못했습니다. 처음에는 PCB에 잘못된 연결이 있었고 새로운 업데이트로 PCB를 다시 주문했지만 제대로 작동할 때까지 몇 번 더 시도해야 했습니다. 

기사의 이 섹션은 아직 작성 중입니다. 나중에 확인하시기 바랍니다….


제조공정

  1. Arduino Sunflower:일렉트로닉 썬댄서
  2. USB MIDI 어댑터
  3. 도구가 의도적으로 "패시베이션"된 이유
  4. 소화전
  5. CNC Swiss Machine은 어떻게 터닝에서 탁월합니까?
  6. 유성 기어 감속기에 대한 심층 분석
  7. Pixie:Arduino 기반 NeoPixel 손목시계
  8. 머시닝이란? – 정의, 프로세스 및 도구
  9. 스테인리스 스틸
  10. 갈탄 건조용 WTA 기술