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

위치 피드백을 갖춘 정밀 선형 서보 액추에이터 구축 – 단계별 가이드

이 튜토리얼에서는 선형 서보 액추에이터를 만드는 방법을 배웁니다. 전압이 가해지면 특정 방향으로 움직이는 일반 선형 액추에이터와 달리 이 맞춤형 선형 서보 액추에이터는 쉽게 제어할 수 있는 정밀하고 반복 가능한 움직임을 제공합니다.

서보 액추에이터라고 불리는 이유는 액추에이터 출력 모션을 정확하게 제어할 수 있는 피드백 루프 시스템을 갖추고 있기 때문입니다.

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

개요

이 리니어 서보 액츄에이터를 제어하기 위한 입력은 아날로그 또는 디지털일 수 있습니다. 아날로그 입력의 경우 여기에 표시된 것처럼 모든 유형의 전위차계가 될 수 있습니다. 선형 전위차계, 일반적인 회전 전위차계 또는 다시 회전 전위차계인 조이스틱 등.

디지털 입력의 경우 RC Transmitter를 이용하여 Actuator를 제어할 수 있습니다. 물론, 이 설정을 위해서는 액추에이터에 대한 입력으로 사용되는 RC 수신기도 필요합니다.

이러한 아날로그 및 디지털 입력 모드 모두 연결을 위해서는 3개의 전선만 필요하며, 그 중 2개는 입력 장치에 전원을 공급하고 세 번째는 입력 신호에 사용됩니다.

이 맞춤형 선형 서보 액츄에이터의 멋진 기능은 출력 로드의 맞춤형 시작 및 끝 위치를 설정할 수 있을 뿐만 아니라 감도를 조정하거나 액츄에이터가 입력에 얼마나 빨리 반응할지를 조정할 수 있다는 것입니다. 

하지만 제가 가장 좋아하는 기능은 직렬 포트 통신을 통해 PC나 노트북에서 이 액추에이터를 제어할 수 있는 기능입니다. Arduino IDE 직렬 모니터를 통해 밀리미터 단위로 값을 입력하면 액추에이터가 해당 위치로 이동합니다.

더 멋진 점은 직렬 모니터에서 원하는 각 위치에 "save"를 입력하여 반복 가능한 움직임을 만들거나 위치를 저장할 수 있다는 것입니다. 그런 다음 직렬 모니터에 "run"을 입력하여 루프에서 동작을 반복하도록 액추에이터에 지시할 수 있습니다.

이제 이 맞춤형 선형 서보 액추에이터에 대해 알아야 할 모든 것과 작동 방식, 설계 방법을 설명하겠습니다. 따라서 여러분도 직접 만들 수도 있습니다. 

작동 방식

따라서 폐쇄 루프 제어 시스템은 AS5600 자기 회전 위치 센서와 DC 모터 구동을 위해 구현된 PID 제어를 기반으로 합니다.

실제로 저는 이전 비디오에서 만든 것과 동일한 맞춤형 서보 모터 컨트롤러 보드를 사용하고 있습니다. 여기에는 자체 마이크로컨트롤러와 모든 DC 모터를 독립형 서보 모터로 쉽게 전환할 수 있는 모든 것이 포함되어 있습니다.

서보 모터와 폐쇄 루프 제어 시스템이 어떻게 작동하는지에 대한 자세한 설명을 보려면 해당 튜토리얼을 확인하세요.  

정말 빠르게, 서보 모터는 입력 신호 또는 원하는 위치가 위치 피드백 센서에서 얻은 모터의 실제 위치와 비교되는 폐쇄 루프 제어 시스템입니다.

오류라고 불리는 발생하는 차이는 모터가 원하는 위치에 도달할 때까지 움직이도록 명령하는 컨트롤러에서 처리됩니다. 

따라서 이 선형 서보 액츄에이터는 서보 모터와 동일한 작동 원리를 가지고 있지만 리드 스크류 메커니즘을 사용하여 모터의 회전 운동을 선형 운동으로 변환하는 추가 단계가 있습니다.

리니어 서보 액츄에이터 디자인

다음은 이 선형 서보 액추에이터의 3D 모델입니다. 여기에서 모든 것이 어떻게 작동하는지 확인할 수 있습니다.

AS5600 자기 회전 위치 센서는 액추에이터 뒷면에 위치하며 리드 스크류의 회전을 추적합니다. 제가 사용하는 리드 스크류의 피치는 8mm입니다. 즉, 한 바퀴 완전히 회전할 때마다 리드 스크류 너트가 8mm의 선형 운동을 한다는 의미입니다.

AS5600은 12비트 인코더이므로 회전당 4096개의 위치를 출력할 수 있습니다. 8을 4096으로 나누면 0.001953mm의 해상도를 얻게 됩니다. 이는 AS5600 인코더가 감지할 수 있는 가장 작은 위치 변화입니다. 내 생각엔 꽤 인상적이다. 

제가 사용하는 DC 모터는 480RPM을 출력하는 감속 기어박스가 포함된 12V 모터입니다. 480을 60으로 나누면 초당 8회전의 값을 얻고, 이 숫자에 8을 곱하면 리드 스크류의 피치가 8mm이므로 액추에이터의 선형 속도는 64mm/s가 됩니다.

이 액추에이터 로드의 최대 이동 거리가 150mm이므로 최대 속도에서 시작부터 끝까지 약 2.5초가 걸리고 가속 및 감속을 포함하면 약 3초가 걸리기 때문에 이 사실이 현장에 있다는 것을 알았습니다. 따라서 리드 스크류를 구동하기 위해 기어 세트 비율을 1:1로 사용했습니다. 

전체 선형 액추에이터의 설계는 맞춤형 서보 모터 컨트롤러 PCB의 크기와 리드 스크류 및 리드 스크류 너트를 기반으로 합니다. PCB의 크기는 40x40mm로 실린더 블록의 최소 크기였습니다.

8mm 리드 스크류 너트의 외부 치수는 22mm이므로 이에 맞춰 로드를 설계했습니다. 너트와 로드는 4개의 M3 볼트와 나사산 인서트로 연결됩니다. 로드 상단에는 실린더 블록을 미끄러지게 하는 베어링이 있어 로드를 가이드하고 회전을 방지하는 역할을 합니다. 

출력 실린더 캡에는 로드를 실린더 블록 밖으로 안내하는 4개의 작은 베어링이 있습니다.

전체적으로 리니어 액츄에이터는 사용된 모든 구성 요소를 고려해 볼 때 충분히 컴팩트하게 나온 것 같습니다.

또한 원점 복귀 및 액추에이터의 시작 위치 설정에 사용되는 마이크로 리미트 스위치를 실린더 블록 내부에 장착했습니다.

3D 모델 다운로드

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

3D 프린팅에 필요한 STL 파일과 이 3D 모델의 STEP 파일을 Cults3D에서 얻을 수 있습니다.

여기서 더 언급할 점은 실린더 블록과 로드의 길이를 늘리는 것만으로 이 선형 액추에이터의 최대 이동 길이를 쉽게 늘릴 수 있다는 것입니다. 저는 모든 부품이 220x220mm의 더 작은 프린트 베드를 갖춘 3D 프린터에 맞도록 하기 위해 이러한 치수를 선택했습니다. 여기서 가장 큰 부분은 길이가 215mm인 로드이다.

3D 프린팅

나의 새로운 Creality Ender-3 V3 SE는 Y축을 따라 가로 방향으로 인쇄하는 데 훌륭한 역할을 했습니다. 약간의 전송 작업이 필요하지만 로드를 이 방향으로 인쇄하면 작업이 더 원활해지고 로드가 더 튼튼해집니다.

3D 프린팅 시 필라멘트의 팽창을 보상하고 보다 정확한 치수의 부품을 얻으려면 슬라이싱 소프트웨어의 수평 확장 기능을 사용하는 것이 중요합니다.

저는 –0.1mm의 값을 사용했지만, 어떤 값이 귀하의 3D 프린터에 적합한지 확인하려면 몇 가지 테스트 프린트를 수행해야 합니다. 

많은 서포트 재료를 인쇄하는 것을 피하기 위해 Z축을 따라 실린더 블록을 인쇄했습니다. Creality Ender-3 V3 SE는 이 인쇄에서도 훌륭한 작업을 수행했습니다.

가격 대비 이 3D 프린터가 제공하는 인쇄 품질에 놀랐습니다. 3D 프린터 설정은 매우 쉽습니다. 자동 베드 레벨링, 직접 압출기, 우수한 인쇄 품질 및 최대 250mm/s의 향상된 인쇄 속도를 갖추고 있습니다. 이 모든 것이 200달러 미만의 가격으로 제공되므로 예산이 부족한 사람들을 위한 최고의 3D 프린터 중 하나입니다.

Creality 매장에서 이 3D 프린터를 확인해 보세요. 또는 아마존 . 또한 내 웹사이트에서 자세한 리뷰를 확인하세요.

조립

어쨌든, 여기에 3D 프린팅된 부품이 모두 있으므로 이제 선형 액추에이터 조립부터 시작할 수 있습니다.

부품 목록

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

기계적:

전자제품:

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

리드 스크류 메커니즘 조립

먼저, 실린더 베이스 블록의 제자리에 리드 스크류를 설치해야 합니다. 이를 위해 먼저 리드 나사와 동일한 나사산이 있는 3D 프린팅 너트를 삽입해야 합니다.

너트를 리드 스크류에 꼭 맞게 조이는 것은 약간 어렵지만 여기서는 이것이 필요합니다. 이 너트는 로드가 밀릴 때 전체 힘을 유지하므로 단단히 끼워질수록 더 많은 힘을 견딜 수 있습니다. 그 외에도 너트에는 그러브 나사로 너트를 샤프트에 고정하기 위한 나사형 인서트를 삽입하기 위한 구멍도 있습니다.

리드스크류는 외경이 22mm인 두 개의 볼 베어링을 사용하여 실린더 베이스 블록에 고정되어 있습니다.

뒤쪽에는 리드 스크류를 구동하는 기어가 있습니다. 이 기어에는 또한 일치하는 나사산과 그러브 나사로 리드 나사에 고정하기 위한 나사산 인서트용 구멍 2개가 있습니다.

이 연결은 모터의 전체 토크를 리드 스크류로 전달하여 미끄러지지 않도록 하므로 매우 중요합니다. 

이 하위 어셈블리를 만들려면 먼저 기어와 너트뿐만 아니라 실린더 블록에도 나사형 인서트를 제자리에 설치해야 합니다.

기어와 너트를 반대 방향으로 조이되 베어링에 축 방향 힘이 추가되므로 너무 조이지 않게 조입니다. 그런 다음 그러브 나사를 사용하여 너트와 기어를 리드 나사에 고정할 수 있습니다.

일단 고정되면 리드 스크류가 아직 제자리에 고정되지 않은 것을 알 수 있습니다. 베어링이 실린더 블록의 제자리에 유지되도록 하려면 이 플레이트를 실린더 블록에 추가해야 합니다.

이로써 이 하위 어셈블리가 완성되었습니다. 이제 리드 스크류가 자유롭게 회전할 수 있으면서도 제자리에 단단히 고정됩니다. 

다음으로 막대를 준비할 수 있습니다. 로드는 리드 스크류를 수용할 수 있도록 전체 길이에 걸쳐 비어 있습니다. 리드 스크류 너트와 로드를 연결하려면 먼저 나사형 인서트를 설치해야 합니다. 

로드 상단에는 외경 13mm, 내경 6mm의 가이드 베어링을 설치해야 합니다.

3D 프린팅된 6mm 중공축에 베어링을 배치하고 길이 10mm의 M3 접시머리 나사를 사용하여 로드에 고정합니다. 이제 막대가 준비되었으며 실린더의 가이드 레일에서 어떻게 미끄러지는지 확인할 수 있습니다.

다음으로 실린더를 실린더 베이스 블록에 부착해야 합니다. 하지만 그 전에 마이크로 리미트 스위치를 제자리에 설치해야 합니다.

먼저 NC 연결부에서 와이어를 납땜해야 합니다. 전선의 길이는 약 15cm 여야 합니다. 와이어는 실린더 상단에 있는 구멍을 통과한 다음 8mm 길이의 M2 볼트 2개를 사용하여 마이크로 리미트 스위치를 실린더에 고정할 수 있습니다.

가이드 베어링이 다른 것을 건드리지 않고 적절한 시간에 트리거하려면 특히 이 마이크로 리미트 스위치가 필요합니다.

물론 정확한 리미트 스위치 모델을 찾을 수 없다면 구멍과 메커니즘을 수정할 수 있습니다. 

실린더를 베이스 블록에 부착하려면 여기에 나사형 인서트 몇 개를 설치해야 합니다. 그런 다음 25mm 길이의 M4 볼트 2개를 사용하여 제자리에 고정할 수 있습니다. 이때 위쪽 볼트 2개만 삽입하면 됩니다.

아래쪽 두 개는 동일한 구멍이 커버 고정에 사용되기 때문에 기어박스와 PCB 커버를 설치할 때 조금 나중에 진행됩니다. 

다음으로 로드를 리드 스크류에 나사로 고정할 수 있습니다. 가이드 베어링은 실린더의 가이드 레일 사이에 들어가야 합니다.

뒤쪽의 기어를 회전시키면 로드가 마이크로 리미트 스위치에 도달할 때까지 뒤로 이동합니다. 

그런 다음 실린더 캡을 제자리에 부착할 수 있습니다. 실린더 캡은 외경이 9mm인 작은 베어링 4개를 수용합니다. 이 베어링의 샤프트는 3D 프린팅이 가능합니다.

이 축이 들어가는 부분이 아주 작아서 쉽게 부러질 수 있으므로 제자리에 삽입할 때 주의해야 합니다. 나에게 그런 일이 몇 번 일어났으므로 그들이 쉽게 맞는지 확인하십시오. 이 베어링은 보다 원활한 작동을 위해 로드를 지지하고 안내합니다.

실린더 캡은 M4 볼트 4개로 제자리에 고정되어 있습니다.

DC 모터 설치

자, 다음으로 DC 모터를 제자리에 삽입해 보겠습니다. 6개의 M3 볼트로 DC 모터를 고정합니다. 그런 다음 모터 샤프트에 기어를 설치할 수 있습니다.

기어를 제자리에 고정하기 위해 두 개의 스레드 인서트와 그럽 나사를 사용합니다. 

기어가 제대로 페어링되면 선형 액추에이터 뒷면에 기어와 PCB 커버를 부착하는 작업을 진행할 수 있습니다. 이를 위해 먼저 실린더 베이스 블록에 나사형 인서트 몇 개를 더 설치해야 합니다.

그런 다음 전선을 DC 모터에 연결할 수 있습니다. 제 경우에는 DC 모터에 직접 납땜했습니다.

전선의 길이는 약 20cm가 되어야 합니다. 실린더 베이스 블록에는 DC 모터와 리미트 스위치의 와이어를 모두 통과시켜야 하는 구멍이 있습니다.

그런 다음 덮개에 있는 두 개의 홀더를 통해 장치를 통과시켜 장치에서 멀리 떨어져 있는지 확인해야 합니다. 

이 시점에서 베이스 블록에 커버를 고정할 수 있습니다. 이를 위해 먼저 아래쪽에 두 개의 M4 볼트를 삽입해야 하지만 완전히 삽입하지는 않습니다.

커버 홀더를 사이에 놓을 수 있도록 2mm~3mm 정도 남겨둔 다음 해당 볼트를 커버와 함께 고정해야 합니다.

이 전체 작업이 조금 지저분하지만, 커버를 최대한 작게 하고 단일 인쇄를 원했고 PCB 홀더가 볼트의 길을 막고 있었기 때문에 그렇게 해야 했습니다.

맞춤형 서보 컨트롤러 PCB 설치

어쨌든 덮개 작업이 끝나면 맞춤형 서보 모터 컨트롤러 보드를 제자리에 설치할 수 있습니다. 제가 말했듯이 이 컨트롤러는 DC 모터를 서보 모터로 바꾸는 방법을 보여드린 이전 동영상과 동일한 컨트롤러입니다.

여기서 주요 구성 요소는 출력 샤프트에 부착된 자석의 각도 위치를 추적하는 AS5600 자기 회전 위치 인코더입니다. 이 경우 리드 스크류의 출력 기어에 자석을 부착합니다. PCB가 제자리에 놓이면 자석이 AS5600 센서와 완벽하게 정렬됩니다.

PCB를 고정하려면 먼저 홀더 슬롯에 M2 너트를 삽입한 다음 M2 볼트 4개로 PCB를 조여야 합니다.

이제 남은 일은 전선을 제자리에 연결하는 것입니다. DC 모터 배선은 모터 단자대에 연결되며 컨트롤러 프로그램과 일치하도록 극성을 추가적으로 확인해야 합니다.

실제로 모터를 PCB에 연결하기 전에 모터에 약간의 전압을 가하여 리드 스크류 메커니즘이 제대로 작동하는지 확인할 수 있습니다.

리미트 스위치 전선의 경우 이 용도에 맞는 전용 핀이 없기 때문에 접지선을 전해 콘덴서의 접지 패드에 납땜하고 NC 연결선을 ATMEGA328 마이크로 컨트롤러의 디지털 핀 번호 13인 SCK 핀에 납땜했습니다.

전원 단자대는 커버 옆면 바로 옆에 있어서 5.5mm 전원 커넥터를 연결할 수 있는 구멍이 있습니다.

또한 DC 모터 드라이버에 방열판을 추가했습니다. 마지막으로 뒷면에 스냅핏 뚜껑을 놓으면 이 프로젝트가 완료됩니다. 

이제 모든 유형의 전위차계 또는 RC 수신기를 적절한 입력 핀에 연결할 수 있으며 이를 통해 선형 액추에이터의 위치를 제어할 수 있습니다.

이미 언급했듯이 이전 비디오에서는 이 컨트롤러의 작동 방식, 회로도 및 PCB 제작 방법을 자세히 설명했습니다.

따라서 이 컨트롤러 보드를 만들고 싶다면 해당 튜토리얼을 확인해야 합니다. 

회로도

아주 빠르게, 주요 구성 요소는 액추에이터 출력의 위치를 추적하는 AS5600 자기 센서입니다. 센서 데이터는 이 서보 컨트롤러 보드인 Atmega328 마이크로 컨트롤러의 두뇌로 들어가 수학을 수행하고 DRV8871 DC 모터 드라이버에 DC 모터 구동 방법을 알려줍니다.

DRV8871 DC 모터 드라이버는 최대 3.6A의 피크 전류를 처리할 수 있습니다. 보드에 전원을 공급하기 위해 12V를 사용한 다음 Atmega328 및 기타 5V 구성 요소용 ASM1117 전압 조정기를 사용하여 5V로 낮출 수 있습니다. 아날로그, 디지털 또는 직렬 포트 통신을 통해 액추에이터의 입력 모드를 선택하는 2채널 DIP 스위치가 있습니다.

트리머 전위차계 중 하나는 액추에이터의 감도를 조정하는 데 사용되며 SDM 푸시 버튼은 시작 및 끝 위치를 설정하는 데 사용됩니다.

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

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

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

어쨌든, 물론 이 맞춤형 서보 컨트롤러 없이도 이 선형 액추에이터 프로젝트를 만들 수도 있습니다.

DC 모터 제어를 위해 Arduino 보드와 함께 브레이크아웃 보드의 AS5600 센서를 사용할 수 있습니다.

코드

이제 이 선형 서보 액추에이터의 코드를 살펴보겠습니다.

/*
 Linear Servo Actuator - 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 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;
//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 setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = ""; // string to hold input
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 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(setButton, INPUT_PULLUP);
 pinMode(inputSwitch, INPUT_PULLUP);
 pinMode(modeSwitch, INPUT_PULLUP);
 pinMode(limitSwitch, INPUT_PULLUP);
 // PID Setup
 myPID.SetMode(AUTOMATIC);
 myPID.SetOutputLimits(-255, 255);
 myPID.SetSampleTime(20);
 // --- HOMING ----
 // Move backward until you ...
 while (digitalRead(limitSwitch) != 1) {
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, 70);
 encoderValue = as5600.readAngle();
 }
 while (digitalRead(limitSwitch) != 0) {
 analogWrite(motor_IN1, 50);
 digitalWrite(motor_IN2, LOW);
 }
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 startPosition = as5600.readAngle() * 0.087890625;
 endPosition = 6000;
 Setpoint = startPosition;
 // --- HOMING End ---
}
void loop() {
 // Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
 // Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }
 // Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }
 
 // Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }
 }
 // Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }
 
 // Confine the minimum and maximum values of the setpoint
 if (Setpoint > endPosition) {
 Setpoint = endPosition;
 }
 if (Setpoint < startPosition) {
 Setpoint = startPosition;
 }
 // Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);
 // Read encoder - use that value as an input for the PID control
 readEncoder();
 // Run motor
 runMotor();
 // Set start and end positions by pressing the "set" button
 if (digitalRead(setButton) == LOW) {
 delay(3000);
 if (digitalRead(setButton) == LOW) {
 endPosition = totalDistance;
 while (digitalRead(setButton) != HIGH)
 ;
 } else {
 startPosition = totalDistance;
 }
 }
}
void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 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 (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}
Code language: PHP (php)

코드 설명

따라서 엔코더 값이나 액츄에이터의 현재 위치를 읽고 이를 밀리미터로 변환하여 루프를 시작합니다.

// Read encoder value - current position
 rodPosition = as5600.readAngle() / 0.001953125; // in millimters - The lead screw is 8mm per rotation, and the encoder RAW value is 4096 per roration, so 8/4096 to get the value in milimiters
Code language: PHP (php)

그런 다음 "직렬 통신 모드"에 있으면 직렬 모니터에 입력한 수신 데이터를 읽습니다. 입력이 "저장"이면 현재 위치 액추에이터를 저장하고, "지우기"이면 이미 저장된 위치를 모두 지웁니다.

// Serial communication mode - Read data from the serial monitor
 if (digitalRead(modeSwitch) == 0) {
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 // If "save" string is sent through the serial monitor, save the current rodPosition into the array
 if (serialInput == "save") {
 positionsArray[positionsCounter] = totalDistance;
 delay(1000);
 positionsCounter++;
 }
 // Clear the saved positions
 if (serialInput == "clear") {
 // Clear the array data to 0
 memset(positionsArray, 0, sizeof(positionsArray));
 positionsCounter = 0;
 }Code language: JavaScript (javascript)

입력이 정수 또는 0에서 150 사이의 숫자인 경우 해당 값을 설정점으로 사용합니다.

// Convert the String to Integer and use it as a Setpoint for the PID control
 serialIntInput = serialInput.toInt();
 if (serialIntInput != 0) {
 if (serialIntInput < 0) {
 serialIntInput = 0;
 }
 if (serialIntInput > 150) {
 serialIntInput = 150;
 }
 Setpoint = serialIntInput * 45; // convert mm into degrees (1mm linear movement equals 45 degrees rotational movement)
 }
 }Code language: JavaScript (javascript)

값을 밀리미터 단위로 입력하지만 회전 샤프트를 추적하기 위해 각도를 사용하므로 밀리미터 값에 45를 곱하여 각도 값으로 변환합니다. 이는 1mm 선형 이동의 경우 리드 스크류가 45도 회전해야 하기 때문입니다. 리드 스크류의 피치가 다른 경우 이 숫자도 달라야 합니다. 

while 및 for 루프를 사용하여 "run"을 입력하면 프로그램은 저장된 위치를 반복적으로 실행합니다.

// Run stored positions
 if (serialInput == "run") {
 while (serialInput != "stop") {
 for (int i = 0; i <= positionsCounter - 1; i++) {
 if (serialInput == "stop") {
 break;
 }
 while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
 // Desired position / setpoint for the PID contorller
 Setpoint = positionsArray[i];
 // Read encoder - use that value as an Input for the PID control
 readEncoder();
 // Run motor - PID controller inside
 runMotor();
 
 }
 delay(2000); // Delay between steps 
 // Check the serial monitor for a stop command
 while (Serial.available() > 0) {
 serialInput = Serial.readString();
 serialInput.trim();
 }
 }
 }
 }Code language: JavaScript (javascript)

반면에 전위차계 및 RC 수신기 제어 모드에 있는 경우 아날로그 또는 디지털 입력이 있는지 확인합니다.

// Potentiometer and RC Receiver control mode
 else if (digitalRead(modeSwitch) == 1) {
 if (digitalRead(inputSwitch) == 0) { // Analog input - Potentiometer
 // Get value from potentiometer
 desiredValue = analogRead(A0);
 if (desiredValue < 15) {
 desiredValue = 15;
 }
 if (desiredValue > 1008) {
 desiredValue = 1008;
 }
 Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
 
 } else if (digitalRead(inputSwitch) == 1) { // Digital input - RC transmitter
 desiredValue = pulseIn(ch1, HIGH, 30000); // Read RC receiver as input
 if (desiredValue < 1000 || desiredValue > 2000) {
 desiredValue = 1000;
 }
 Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
 }
 }Code language: JavaScript (javascript)

아날로그인 경우 전위차계에서 아날로그 입력을 읽고 해당 값을 설정점 또는 액추에이터가 이동할 원하는 위치로 사용합니다. 마찬가지로 입력이 디지털인 경우 RC 수신기에서 들어오는 데이터를 읽고 해당 값을 설정점으로 사용합니다. 

그런 다음 readEncoder() 및 runMotor() 사용자 정의 함수를 호출하여 액츄에이터의 현재 위치를 읽고 PID 제어를 실행합니다. readEncoder() 함수를 사용하여 센서의 현재 값을 각도 값으로 읽고, if 문을 사용하여 샤프트의 현재 위치가 어느 사분면에 있는지 추적합니다.

void readEncoder() {
 // Convert encoder RAW values into angle values for keeping track of the angular position of the shaft
 encoderValue = as5600.readAngle() * 0.087890625;
 // Quadrant 1
 if (encoderValue >= 0 && encoderValue <= 90) {
 quadrantNumber = 1;
 }
 // Quadrant 2
 if (encoderValue >= 90 && encoderValue <= 180) {
 quadrantNumber = 2;
 }
 // Quadrant 3
 if (encoderValue >= 180 && encoderValue <= 270) {
 quadrantNumber = 3;
 }
 // Quadrant 4
 if (encoderValue >= 270 && encoderValue <= 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 (totalDistance >= 0) {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 } else {
 totalDistance = (numberOfTurns * 360) + encoderValue;
 }
 // Establish Input value for PID
 Input = totalDistance; // current value of the position
}Code language: HTML, XML (xml)

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

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

// Adjusting sensitivity
 //Pk1 = analogRead(A2) * 0.002; // Adjust the PID gain term 
 //myPID.SetTunings(Pk1, Ik1, Dk1);Code language: JSON / JSON with Comments (json)
void runMotor() {
 // Run PID process to get Output value
 myPID.Compute();
 // Move right
 if (Output > 1) {
 pwmValue = Output;
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 analogWrite(motor_IN1, pwmValue);
 digitalWrite(motor_IN2, LOW);
 }
 // Move left
 else if (Output < 1) {
 pwmValue = abs(Output);
 if (pwmValue < 50 && pwmValue > 15) {
 pwmValue = pwmValue + 40;
 }
 if (pwmValue <= 15) {
 pwmValue = 0;
 }
 digitalWrite(motor_IN1, LOW);
 analogWrite(motor_IN2, pwmValue);
 }
 // Do not move
 else if (Output > -1 && Output < 1) {
 pwmValue = 0;
 digitalWrite(motor_IN1, LOW);
 digitalWrite(motor_IN2, LOW);
 }
}Code language: JavaScript (javascript)

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

PID 제어기의 세 가지 항인 비례, 적분, 미분은 상단에 정의되어 있으며 이를 조정하여 다양한 출력 응답을 얻을 수 있습니다.

double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;Code language: JavaScript (javascript)

품질, 액추에이터가 얼마나 잘 작동하는지 또는 입력에 직접적으로 반응하는지는 이러한 값에 따라 달라집니다.

테스트

여기에서는 액추에이터 정확도를 테스트하고 있습니다. 괜찮게 제자리로 돌아옵니다. 그런 다음 A는 막대를 한 번에 1mm씩 움직이기 시작했습니다. 첫 번째 무브먼트는 1mm가 아닌 0.8mm 같았지만 다음 4개의 무브먼트는 1mm에 충분히 가까웠습니다.  그런 다음 4mm 무브먼트는 약 0.15mm 정도 벗어났습니다. 

막대의 백래시가 약 0.25mm라는 점에 유의해야 합니다. 이 백래시는 리드 스크류와 리드 스크류 너트 사이에 있습니다. 게다가 3D 프린팅된 기어와 DC 모터 자체의 기어에도 약간의 백래시가 있을 수 있습니다.  

물론 막대에 힘을 가하고 정확도를 테스트하면 훨씬 더 큰 오류가 발생하지만 PID 컨트롤러를 조정하면 오류를 개선할 수 있습니다. 

그럼에도 불구하고, 이것이 이 튜토리얼의 전부입니다. 재미있게 즐기시고 새로운 것을 배우셨기를 바랍니다.


제조공정

  1. arduino를 사용한 자동화된 Dino 게임
  2. Millwright 채용 정보, 임금 및 경력 정보
  3. 테프론 코팅 자동화 설비로 가공 정밀도 향상
  4. 오일 미스트 공기 청정기 및 건강 문제 정보
  5. 번지 코드
  6. 금속 띠톱날 소개
  7. 가공 제조를 위해 CAD 도면을 준비하는 방법
  8. 알루미늄 합금의 내식성
  9. CNC 와이어 EDM 가공을 수행하는 방법
  10. 프로토타이핑의 다른 유형은 무엇입니까?