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

PWM 읽기, RC 수신기 입력 디코딩, 페일 세이프 적용

구성품 및 소모품

Arduino UNO
× 1
SG90 마이크로 서보 모터
× 2

이 프로젝트 정보

이 프로젝트에는 모든 Arduino 입력 핀에서 RC 수신기(또는 다른 PWM 신호)를 단순히 읽는 데 사용할 수 있는 일반적이지만 효율적인 코드가 포함되어 있으며 송신기 신호가 손실된 경우에도 안전 장치를 적용할 수 있습니다.

아래는 이 페이지 하단에 있는 PWMread_RCfailsafe.ino 코드를 사용하여 서보 믹서로 작동하는 Arduino uno를 보여주는 비디오입니다.

도움이 되는 것은 PWMread_RCfailsafe.ino의 기능이 인터럽트 레지스터를 관리하고 다른 핀을 사용하는 다른 프로젝트 간에 쉽게 이동할 수 있다는 점입니다.

아래 동영상 예시:

<울>
  • 수신기가 송신기로부터 신호를 받지 못할 때 안전 장치가 활성화됩니다. 엘리베이터 채널은 최대로 설정되고 에일러론 채널은 중립으로 설정됩니다.
  • 파란색 서보의 방향은 스로틀 위치에 의해 설정됩니다.
  • 청색 서보의 이동 범위(속도)는 송신기 측면의 슬라이더로 설정됩니다.
  • 트랜스미터의 기어 스위치를 사용하여 믹싱을 켜고 끕니다.
  • 목차

    <울>
  • PWM으로 서보를 제어하는 ​​방법
  • RC 모델/로봇에서 Arduino의 사용 예
  • 코드 개요:안전 장치를 사용하여 RC 수신기의 PWM 디코딩
  • PWMread_RCfailsafe.ino 사용 방법
  • 수신기 프레임 속도 및 주파수 표시
  • 서보 믹싱 예시
  • 취한 접근 방식의 근거
  • 제한 사항
  • 서보와 속도 컨트롤러는 PWM으로 어떻게 제어됩니까?

    이 프로젝트의 나머지 부분에서는 서보 및 속도 컨트롤러를 제어하는 ​​데 사용되는 PWM 신호를 이해하고 있다고 가정합니다. 다음은 이러한 PWM(펄스 폭 변조) 신호의 작동 방식을 설명하는 좋은 비디오입니다.

    또한 다음에 대한 실무 지식이 있어야 합니다.

    <울>
  • Arduino IDE
  • Float, boolean 및 int 변수
  • If 루프
  • For 루프
  • 배열
  • 서보 라이브러리
  • RC 모델/로봇에서 Arduino의 사용 예

    당신은 당신의 상상력에 의해서만 제한될 것입니다:

    <울>
  • 서보 믹싱 적용, 조명 켜기/끄기, 펌프/밸브 제어, 맞춤형 시퀀스 설정...
  • 컨트롤러 생성(예:비행 안정화/자동 조종, 방향 유지, 고도/수심 유지, 자동 수평 조정, 감지 및 회피, 귀가...)
  • RC 모델이 신호 손실 또는 낮은 배터리 전압에 반응하도록 하십시오...
  • 설정을 변경하거나 모델 메모리 기능을 사용하지 않고도 여러 모델/프로젝트에 동일한 송신기를 사용합니다.
  • 코드 개요:안전 장치를 사용하여 RC 수신기에서 PWM 디코딩

    이 코드는 핀 변경 인터럽트를 사용하여 PWM(펄스 폭 변조) 신호를 측정합니다. 사용된 기능은 Arduino Uno, Nano 또는 Pro Mini에서 모든 디지털 또는 아날로그 핀(A6 및 A7 제외)에서 인터럽트 설정 및 데이터 추출을 자동화합니다. 따라서 초보자도 코드를 쉽게 사용할 수 있습니다.

    이 프로젝트의 주요 목표는 프로젝트 간에 신속하게 이동할 수 있는 안전 장치 "모듈"이 있는 일반 RC 수신기를 만드는 것이었습니다. 따라서 "사용 방법" 섹션에 표시된 예제 코드는 목적을 위한 수단으로 사용할 수 있습니다.

    참고: 이 코드는 소프트웨어 직렬 또는 핀 변경 인터럽트를 사용하는 다른 라이브러리에서 작동하지 않습니다.

    코드 작동 방식에 관심이 있는 사용자:

    <울>
  • 입력 핀은 배열에서 식별됩니다. 이 배열의 길이는 제한이 없습니다.
  • 설정 기능은 핀 배열에 나열된 각 핀에 대해 적절한 레지스터를 설정하여 핀 변경 인터럽트를 활성화합니다.
  • 선택된 핀의 전압 변경은 핀이 ISR(PCINT0_vect) -> 포트 B, ISR(PCINT1_vect) -> 포트 C에 속하는 포트 레지스터에 따라 세 가지 ISR(Interrupt Service Routes) 중 하나를 트리거합니다. ISR(PCINT2_vect) -> 포트 D.
  • 각 ISR 내에서 FOR 루프와 IF 문은 어떤 핀이 변경되었고 어떤 RC 채널에 속하는지 확인하는 데 사용됩니다. 인터럽트 시간은 기본 루프()로 돌아가기 전에 micros()를 사용하여 기록됩니다.
  • 핀 변경 사이의 시간 간격은 펄스 폭 및 반복 주기를 계산하는 데 사용됩니다.
  • 각 ISR에 플래그가 설정되어 새 펄스가 수신되었음을 나타냅니다.
  • 이 플래그는 나머지 기능에서 ISR에서 수집한 데이터를 추출 및 처리하는 데 사용됩니다.
  • 다음 YouTube 동영상 제작 Joop Brokking은 RC 수신기를 arduino에 연결하는 동일한 방법을 사용하는 다른 프로젝트에 대해 이야기합니다. 처음 8분 동안 Joop은 방법을 명확하게 설명합니다. 핀 변경 인터럽트를 사용하여 RC 수신기의 PWM 신호를 측정합니다.

    이 모든 세부 정보는 이 페이지 하단에서 다운로드할 수 있는 PWMread_RCfailsafe.ino에서 관리합니다.

    포트 조작에 대한 몇 가지 유용한 정보도 여기에서 찾을 수 있습니다. https://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/

    핀 변경 인터럽트 처리 외에도 전용 함수 RC_decode()가 작성되어 펄스 폭(1000-2000uS)을 송신기의 +-100% 제어 신호로 변환합니다. 안전 장치는 10-330Hz 및 500-2500uS의 신호 허용 오차를 사용하여 유효한 송신기 신호를 확인합니다. 신호가 손실되면 RC_decode()는 미리 결정된 안전 장치 값을 반환합니다.

    PWMread_RCfailsafe.ino에서 각 채널에 대해 특정 송신기에 대한 보정 값과 안전 장치 위치를 설정할 수 있습니다.

    PWMread_RCfailsafe.ino 사용 방법

    1단계: 하드웨어 설정 함께 아두이노 우노

    Arduino Uno로 예제 설정을 따르는 경우 수신기를 다음과 같이 연결합니다. (그렇지 않으면 자신의 프로젝트를 사용하는 경우 2단계로 바로 이동)

    <울>
  • 5v 및 GND 핀을 사용하여 수신기에 전원 공급
  • 암-수 점퍼 와이어를 사용하여 수신기의 신호 핀을 Arduino의 핀 2 ~ 7에 연결합니다. (2채널 수신기가 있는 경우 핀 2와 3에만 연결)
  • 서보 믹서의 경우 하나의 서보 신호 와이어를 핀 9에 연결하고 다른 하나를 핀 10에 연결합니다.
  • 2단계:PWMread_RCfailsafe.ino를 스케치 폴더에 복사

    예제 스케치 RC_Read_Example은 페이지 하단에서 다운로드할 수 있도록 포함되어 있습니다. 아래 단계를 수행할 때 이것을 기본 스케치로 사용할 수 있습니다.

    기본 스케치가 포함된 폴더에 PWMread_RCfailsafe.ino 파일을 복사하여 붙여넣습니다. 다음에 IDE에서 스케치를 열면 PWMread_RCfailsafe.ino 내의 코드가 포함된 두 번째 탭이 나타납니다.

    3단계:지정 입력

    Arduino IDE에서 기본 스케치를 열거나 다시 엽니다.

    PWMread_RCfailsafe 탭을 클릭하고 "USER DEFINED VARIABLES" 제목으로 스크롤한 다음 pwmPIN[] 배열에 입력 핀을 입력합니다.

    참고: 핀을 원하는 수와 순서로 사용할 수 있습니다. 입력이 많을수록 코드가 인터럽트 루틴을 처리하는 데 더 많은 시간을 할애할 수 있다는 점에 유의하십시오. 참고 A6 및 A7은 아날로그 전용 핀이며 사용할 수 없습니다.

    Arduino MEGA는 현재 지원되지 않지만 필요하다면 쉽게 해결할 수 있습니다.

    참고: pwmPIN[]의 첫 번째 요소는 채널 1이고 두 번째 요소는 채널 2 등입니다. 수신기의 모든 채널을 사용하는 경우 수신기 채널 1이 채널에 해당하는지 확인하는 것이 좋습니다. 1 in pwmPIN[]...

    4단계: 검토 사용 가능 기능 안에 PWMread_RCfailsafe.ino

    5단계: 인쇄 펄스 너비 데이터 ~에 연속

    RC_Read_Example 코드를 업로드하고 송신기를 켜고 원시 펄스 폭 데이터를 직렬로 인쇄하십시오.

    RC_avail() 함수를 사용하여 모든 채널에서 새 데이터가 수신된 시점을 확인한 다음, print_RCpwm()을 사용하여 펄스 폭 데이터를 직렬로 보내야 합니다.

    6단계: 송신기 보정

    각 채널을 +-100% 범위로 보정하기 위해 RC_min[], RC_mid[] 및 RC_max[] 배열의 값을 수동으로 수정하기 위해 print_RCpwm()을 통해 직렬로 인쇄된 펄스 폭 데이터를 사용합니다.

    7단계:보정된 채널 인쇄 ~에 연속

    print_RCpwm() 함수를 주석 처리

    RC_decode(channel) 함수를 사용하여 각 채널을 +-1 범위로 보정하십시오.

    그런 다음 decimal2percentage() 함수와 Serial.println("")

    을 차례로 사용하여 보정된 각 채널을 직렬로 인쇄합니다.

    8단계: 페일 세이프 설정

    각 채널에 대한 RC_failsafe[] 배열의 안전 장치 위치를 조정합니다(범위 +-1).

    트랜스미터를 켜고 끄고 페일 세이프가 원하는 대로 작동하는지 확인합니다.

    이제 스케치에서 RC 입력을 사용할 수 있습니다.

    참고: 수신기의 모든 안전 장치 기능을 비활성화해야 할 수 있습니다. 그렇지 않으면 arduino가 송신기 신호 손실에 응답할 수 없습니다.

    수신기 프레임 속도 및 주파수 표시

    수신기 펄스 반복 주기 및 주파수를 직렬로 인쇄할 수 있습니다. PWM_period() 및 PWM_freq()를 사용하여 인쇄용 데이터를 추출하기 전에 PWM_read(채널 번호) 함수를 사용하여 선택한 채널에서 새 데이터를 사용할 수 있는지 확인하십시오. 예제 코드는 RC_FrameRate.ino에서 사용할 수 있습니다.

    첫 번째 채널은 각 수신기 프레임에서 전송되는 첫 번째 펄스가 되므로 사용하는 것이 가장 좋습니다. PWM_read()는 RC_decode(CH)와 동일한 플래그를 사용하므로 PWM_read()가 먼저 호출되는지 확인하십시오.

    아래 스크린샷 참조:

    수신자 기간은 다음 데이터 세트가 도착하기 전에 코드에 얼마나 많은 시간이 있는지 알려 주기 때문에 알면 유용할 수 있습니다. RC_avail()이 미리 결정된 시간(예:21ms) 후에 새 RC 데이터를 감지하지 못하면 RC_decode()를 실행하여 안전 장치를 트리거하거나 안정적인 주파수에서 프로그램(PID 컨트롤러일 수 있음)을 계속 실행합니다.

    이것은 다음 if 문에 의해 RC_Read_Example.ino에서 달성됩니다.

    now =millis();if(RC_avail() || now - rc_update> 21) rc_update =now; // RC_decode()를 사용하여 RC 입력 데이터 업데이트 // PID 컨트롤러 실행 // 서보 믹싱 적용 // 서보 위치 지정} 

    서보 믹싱 예시

    두 개의 수신기 채널(이 경우 채널 2와 3, 엘리베이터 및 에일러론)을 혼합하는 방법을 보여주기 위해 RC_ServoMixer_Example.ino를 포함했습니다. 스케치는 또한 서보 방향, 비율 및 하위 트림을 설정하는 방법을 보여줍니다. 서보 라이브러리는 핀 9와 10을 통해 서보를 제어하는 ​​데 사용됩니다.

    다음은 코드의 서보 믹싱 섹션의 스크린샷입니다.

    믹스는 단순히 두 채널을 더하거나 빼고 출력을 -1 ~ +1 범위로 제한하여 이루어집니다. 엘리베이터와 에일러론 혼합을 적용할 때 각 서보에 대해 하나씩 두 개의 출력을 생성합니다.

    mix1 =채널 2 - 채널 3(엘프 - 모든)

    mix2 =채널 2 + 채널3(엘프 - 모든)

    서보를 배치하기 전에 +-100%(+-1) 신호를 서보에 대한 마이크로초 단위의 동등한 펄스 폭으로 변환해야 합니다. RC_ServoMixer_Example.ino에서 calc_uS() 함수를 사용하여 이를 수행합니다. 이 기능은 스케치 하단에 배치되며 아래 스크린샷과 같습니다.

    각 서보에 대해 지정된 방향, 속도 및 서브 트림은 서보에 대한 적절한 펄스 폭을 계산하는 데 사용됩니다.

    표준 중성 펄스는 1500uS이고 중성선 양쪽의 정상 범위는 +-500uS입니다. 이것은 1000uS(-100%)의 최소 펄스 폭과 2000uS(+100%)의 최대 펄스 폭을 제공합니다. 따라서 비율, 방향 및 서브 트림이 적용된 펄스는 다음과 같이 계산할 수 있습니다.

    펄스, uS =1500 + (servo_position_% * 속도 * 방향 + 서브 트림) * 500

    서보 방향, 속도 및 서브 트림은 정적이거나 다른 수신기 채널의 입력에 대한 응답으로 스케치에 의해 또는 다른 수단에 의해 동적으로 수정될 수 있습니다.

    접근 방식의 근거

    pulseIn(PIN, HIGH) 함수를 사용하여 RC 수신기를 읽을 수 있지만 pulseIn()은 펄스가 시작되고 끝날 때까지 기다리는 동안 loop()의 코드를 차단하여 귀중한 처리 시간을 낭비합니다. 둘 이상의 입력 데이터가 있는 경우에도 손실될 수 있습니다.

    속도를 위해 루프()의 코드가 최소한의 지연으로 실행될 수 있도록 직접 포트 조작과 함께 Arduino의 핀 변경 인터럽트 기능을 사용하는 것이 가장 좋습니다. 그러나 이것은 단순히 pulseIn(PIN, HIGH)을 호출하는 것보다 더 복잡하고 시간이 많이 걸립니다.

    따라서 프로젝트 간에 이동할 수 있는 몇 가지 일반 코드를 작성하여 두 세계의 이점을 얻고 싶었습니다. 필요한 것은 .ino 파일(함수 및 인터럽트 루틴 포함)을 복사하여 기본 스케치 폴더에 붙여넣고 입력 핀을 지정한 다음 스케치의 기능을 사용하는 것입니다.

    제한 사항

    마이크로() 함수

    arduino에서 마이크로초 타이밍은 micros() 함수를 사용하여 수행됩니다. 이 기능은 4uS 단위로 계산됩니다. 이것은 1000-2000uS 펄스를 측정할 때 4마이크로초 수준의 정밀도를 갖는다는 것을 의미합니다. 실용적인 관점에서 이것은 충분합니다.

    원하는 경우 타이머 인터럽트를 사용하여 이 분해능을 0.5uS로 향상시킬 수 있습니다. 아래 링크 참조:

    https://www.instructables.com/id/How-to-get-an-Arduino-micros-function-with-05us-pr/

    PWMread_RCfailsafe.ino의 효율성

    PWMread_RCfailsafe.ino를 사용하여 6 또는 9 채널 수신기를 읽는 경우 처리 시간의 1.4-2.0%가 핀 변경 인터럽트 루틴을 실행하는 데 사용되며, 이는 수용할 수 있는 것 이상입니다.

    그러나 코드의 한계와 필요한 경우 속도를 높일 수 있는 방법을 이해하는 것이 항상 좋습니다.

    다음은 선택한 입력 채널 수에 따라 각 ISR을 실행하는 데 걸리는 시간 목록입니다.

    1 채널 <8uS

    2채널 <12uS

    3채널 <16uS

    4채널 <20uS

    5개 채널 <20uS

    6채널 <24uS

    참고: 채널이 많을수록 각 ISR을 실행하는 데 더 오래 걸립니다. ISR이 호출될 때마다 for 루프가 각 채널을 통해 실행되기 때문입니다.

    이 추가 시간(비효율)은 저주파(예:50hz) RC 신호를 측정할 때 무시할 수 있습니다.

    위에서 ISR에 들어가고 나가는 데 ~4uS가 걸립니다. 하나의 펄스에 대해 ISR은 펄스 시작 시 한 번(LOW에서 HIGH로), 그리고 끝에서 다시(HIGH에서 LOW로) 두 번 실행됩니다.

    6개의 RC 입력을 사용할 때 1 펄스를 측정하는 데 걸리는 시간은

    2 * (ISR을 입력하려면 4us + ISR을 실행하려면 24uS) =2 * 28 =48uS.

    참고: 측정할 수 있는 최소 펄스 폭입니다.

    6개 채널을 모두 읽는 데 걸리는 시간은 288uS(6 * 48uS)입니다.

    수신기 반복 주기가 20밀리초라고 가정하면 인터럽트는 시간의 1.44%(0.000288/0.02) 동안 실행됩니다. 이것은 pulseIn() 함수를 사용하는 것보다 훨씬 낫습니다. pulseIn()은 각 핀에 대해 최대 20밀리초 동안 코드를 차단합니다.

    참고: arduino에 2개의 RC 입력만 있는 경우 ISR은 시간의 0.16%(0.000032/0.02) 동안만 실행됩니다.

    최대 실제 빈도 (Hz)

    이 코드를 다른 용도로 사용하는 경우 실제 최대 주파수는 2.5kHz입니다. 이것은 micros() 함수에서 100단계의 분해능을 제공합니다(+- 0.025kHz).

    이 주파수에서 하나의 입력 핀을 사용하는 경우 시간의 3%가 인터럽트에서 소비되며, 이는 측정할 수 있는 최소 듀티가 0.03임을 의미합니다. 이것은 12uS의 최소 펄스에 해당합니다.

    더 높은 주파수의 경우 응용 프로그램에 맞게 ISR을 다시 작성하십시오.

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • PWMread_RCfailsafe
  • RC_Read_예제
  • RC_FrameRate
  • RC_ServoMixer_예
  • PWMread_RCfailsafe아두이노
    이 .ino 파일에는 RC 수신기를 디코딩하고 송신기 신호가 손실된 경우 페일 세이프를 적용하는 데 사용되는 기능 및 핀 변경 인터럽트 루틴(ISR)이 포함되어 있습니다. 이 파일을 복사하여 기본 스케치와 동일한 폴더에 붙여넣습니다(스케치를 열 때 이 코드는 arduino IDE에서 두 번째 탭으로 나타납니다). 그런 다음 파일의 지침을 따르십시오.
    /* Kelvin Nelson 24/07/2019 * * 안전 장치가 있는 RC 수신기의 PWM(펄스 폭 변조) 디코딩 * * 이 코드에는 모든 장치에서 구형파 신호를 측정하는 사용하기 쉬운 기능이 포함되어 있습니다. arduiuno pro mini, nano 또는 uno 핀(A6 및 A7 제외). * 이 코드는 RC 수신기와 함께 사용하기 위한 것이지만 대부분의 다른 PWM 측정 애플리케이션에서 pulseIn(PIN, HIGH)을 직접 대체하여 사용할 수도 있습니다. * (현재까지 1khz 이상의 주파수 또는 arduino 메가에서 테스트되지 않았습니다) * * RC 신호 펄스는 각 입력 핀에서 펄스 폭 지속 시간(1000-2000uS)에서 -+100으로 변환될 수 있습니다. 스케치에 사용하기 위한 %(-+1.0) 출력. * 이 변환에 대한 보정과 안전 장치 설정은 각 채널에 대해 설정할 수 있습니다. (fail safe tolerance 10-330Hz 및 500-2500uS). * * 각 핀의 원시 데이터(예:펄스 시간, 펄스 폭, 프레임 길이, 듀티 및 주파수)도 추출할 수 있습니다. * * 설정이 빠르고 이 파일의 구성은 다음과 같습니다. * * - 코드 개요 * - 기능 목록 * - 사용 방법(예제 스케치 포함) * - 사용자 정의 변수 -> 입력 핀 지정, 송신기 교정 및 안전 장치. * - 전역 변수 및 기능 * * 코드 개요:* * 코드는 적절한 레지스터를 설정하여 선택한 핀에서 핀 변경 인터럽트를 활성화합니다. * * 선택한 핀 중 하나에서 전압이 변경되면 핀이 속한 레지스터에 따라 세 가지 인터럽트 서비스 루틴 중 하나가 트리거됩니다. * - ISR(PCINT0_vect), ISR(PCINT1_vect) 또는 ISR(PCINT2_vect) * * 각 ISR 내에서 코드는 변경된 핀을 결정하고 메인 루프()로 다시 돌아가기 전에 시간을 기록합니다. * * 핀 변경 사이의 시간 간격은 펄스 폭과 프레임 길이를 계산하는 데 사용됩니다. * * 플래그는 새 펄스가 수신될 때를 나타내기 위해 ISR에 의해 설정됩니다. * * 그런 다음 플래그는 각 ISR에서 수집한 데이터를 추출하고 처리하는 데 사용됩니다. * * 완전히 같지는 않지만 이 코드는 이 비디오에서 설명한 것과 유사한 원칙을 따릅니다. https://youtu.be/bENjl1KQbvo * */// LIST OF FUNCTIONS:// OUTPUT TYPE NAME OF FUNCTION NOTES// void setup_pwmRead() 핀 변경 인터럽트를 사용하여 PWM 측정을 초기화합니다.// RC RECEIVER DECODING// 부울 RC_avail()은 새 RC 데이터를 사용할 수 있을 때 HIGH를 반환합니다.// float RC_decode(채널 번호)는 선택한 RC 채널을 +-100 범위로 디코딩합니다. %, 그리고 안전 장치를 적용합니다.// void print_RCpwm() RC 채널 원시 데이터를 직렬 포트(교정에 사용됨)에 인쇄합니다.// 일반 PWM MEASUREMENTS// 부울 PWM_read(채널 번호)는 새 펄스가 있을 때 HIGH를 반환합니다. 특정 채널에서 감지됩니다. // 이 함수는 펄스 데이터를 인터럽트 루틴 외부의 변수에 저장하고 // 나머지 PWM 함수를 사용하기 직전에 호출해야 합니다. // unsigned long PWM_time()은 펄스 시작 시 시간을 반환합니다. // float PWM() 펄스 폭 반환// float PWM_period() 펄스 사이의 시간 반환// float PWM_freq() 주파수 계산// float PWM_duty() 듀티 계산// 참고:PWM_read(CH) 및 RC_decode(CH)는 동일한 플래그를 사용 새로운 데이터를 사용할 수 있을 때 감지합니다. 즉, 둘 다 동시에 동일한 채널에서 사용되는 경우 데이터가 손실될 수 있습니다.// 제안:PWM_read(CH)를 사용하여 RC 채널의 프레임 속도를 찾으려면 호출하십시오. RC_decode(CH) 전에. 그러면 RC_decode(CH)의 출력이 기본적으로 안전 장치로 설정됩니다.// 사용 방법(예제 스케치 포함)// 아래 코드의 "USER DEFINED VARIABLES" 제목 아래 //// 1단계:입력 핀을 배열 pwmPIN[] ={}. //// - pwmPIN[]에 임의의 수의 핀을 입력할 수 있습니다(핀은 0 - 13 및 A0 - A5 사용 가능)// - 핀은 숫자 순서일 필요가 없습니다(예:pwmPIN[] ={A0, 5개 채널의 경우 5,6,10,8} 또는 2개 채널의 경우 pwmPIN[] ={A0,5}// - 배열의 첫 번째 요소는 "채널 1"의 핀 번호이고 두 번째 요소는 핀입니다. "채널 2"에 대한 번호... etc.// - RC 수신기에 연결된 모든 핀은 어레이의 시작 부분에 있어야 합니다. 즉, 처음 2개의 채널은 RC 입력이 될 수 있고 세 번째 채널은 초음파 센서의 에코 핀과 같은 다른 장치에 연결될 수 있습니다. //// 2단계:RC 수신기가 모든 입력에 연결된 경우 RC_inputs를 다음으로 설정합니다. 0, 수신기에 연결된 채널 수를 지정하지 않으면 ie RC_inputs =2;//// 3단계:스케치 폴더에 포함된 이 .ino 파일로 간단한 스케치를 업로드하여 송신기를 보정하고 원시 PWM 값을 인쇄합니다. 직렬로 연결합니다(또는 스케치에 필요한 기능을 복사하여 붙여넣기).// 직렬 모니터의 정보를 사용하여 RC_min[], RC_mid[], RC_max[] 배열의 값을 송신기에 맞게 수동으로 업데이트합니다(최대 속도를 사용하여 최상의 해상도를 얻으십시오). // RC 채널 PWM 데이터를 직렬로 인쇄하기 위한 예제 스케치. /* 무효 setup() { setup_pwmRead(); Serial.begin(9600); } 무효 루프() { if(RC_avail()) print_RCpwm(); } */// 4단계:-1.0 ~ +1.0 범위에서 각 채널에 대한 안전 장치 위치를 선택하고 배열에 입력합니다. RC_failsafe[] ={}// 참고:arduino가 응답하도록 하려면 송신기 신호의 손실 수신기의 안전 장치 기능을 비활성화해야 할 수도 있습니다(있는 경우).// 안전 장치의 작동을 확인하고 보정된 채널을 직렬로 인쇄하기 위한 예제 스케치:/* unsigned long now; // 일정한 간격으로 데이터를 업데이트하는 타이밍 변수 unsigned long rc_update; const int 채널 =6; // 수신기 채널 수 지정 float RC_in[channels]; // 수신기에서 보정된 입력을 저장할 배열 void setup() { setup_pwmRead(); Serial.begin(9600); } 무효 루프() { 이제 =millis(); if(RC_avail() || now - rc_update> 25){ // RC 데이터가 사용 가능하거나 마지막 업데이트 이후 25ms가 지난 경우(수신기의 프레임 속도에 맞게 조정) rc_update =now; //print_RCpwm(); // 수신기에서 직렬로 원시 데이터를 인쇄하려면 주석 처리를 제거합니다. for (int i =0; i=0 &&pwmPIN[i] <=7) pwmPIN_port[i] =2; // 핀은 PCINT2_vect(PORT D)에 속합니다. else if (pwmPIN[i]>=8 &&pwmPIN[i] <=13) pwmPIN_port[i] =0; // 핀은 PCINT0_vect(PORT B)에 속합니다. // 핀 번호(즉, 핀 11 또는 핀 A0)를 포트 레지스터의 핀 위치로 변환합니다. 매크로를 사용하여 이 작업을 수행하는 더 좋은 방법이 있을 가능성이 높습니다... // (포트 레지스터에서 직접 핀 상태를 읽으면 ISR의 코드 속도가 빨라집니다.) if(pwmPIN[i] ==0 || pwmPIN[i ] ==A0 || pwmPIN[i] ==8) pwmPIN_reg[i] =0b00000001; 그렇지 않으면 if(pwmPIN[i] ==1 || pwmPIN[i] ==A1 || pwmPIN[i] ==9) pwmPIN_reg[i] =0b00000010; else if(pwmPIN[i] ==2 || pwmPIN[i] ==A2 || pwmPIN[i] ==10) pwmPIN_reg[i] =0b00000100; 그렇지 않으면 if(pwmPIN[i] ==3 || pwmPIN[i] ==A3 || pwmPIN[i] ==11) pwmPIN_reg[i] =0b00001000; 그렇지 않으면 if(pwmPIN[i] ==4 || pwmPIN[i] ==A4 || pwmPIN[i] ==12) pwmPIN_reg[i] =0b00010000; else if(pwmPIN[i] ==5 || pwmPIN[i] ==A5 || pwmPIN[i] ==13) pwmPIN_reg[i] =0b00100000; 그렇지 않으면(pwmPIN[i] ==6) pwmPIN_reg[i] =0b01000000; 그렇지 않으면 (pwmPIN[i] ==7) pwmPIN_reg[i] =0b10000000; }}// SETUP OF PIN CHANGE INTERRUPTSvoid setup_pwmRead(){ for(int i =0; i  num_ch) RC_inputs =num_ch; // RC 수신기에 연결된 핀 수를 정의합니다. } // INTERRUPT SERVICE ROUTINES(ISR) READ PWM INPUT// PCINT0_vect(B 포트 레지스터)는 핀 D8-13.// PCINT1_vect(C 포트 레지스터) "" "" A0-A5의 모든 변경 사항에 반응합니다. // PCINT2_vect(D 포트 레지스터) "" "" D0-7.// 포트 레지스터는 ISR 코드의 if 문 속도를 높이는 데 사용됩니다. // https://www.arduino.cc/en/Reference/PortManipulation http //tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/// http://harperjiangnew.blogspot.co.uk/2013/05/arduino-port-manipulation-on-mega-2560 .html// READ INTERRUPTS ON PINS D8-D13:ISR 루틴은 핀이 변경된 것을 감지하고 PWM 펄스 폭과 펄스 반복 주기를 반환합니다.ISR(PCINT0_vect){ // 이 함수는 포트 B에서 핀 변경이 감지되면 실행됩니다. pciTime =마이크로(); // Record the time of the PIN change in microseconds for (int i =0; i  RC_inputs) return 0; // if channel number is out of bounds return zero. int i =CH - 1; // determine the pulse width calibration for the RC channel. The default is 1000, 1500 and 2000us. int Min; if(CH <=size_RC_min) Min =RC_min[CH-1]; else Min =1000; int Mid; if(CH <=size_RC_mid) Mid =RC_mid[CH-1]; else Mid =1500; int Max; if(CH <=size_RC_max) Max =RC_max[CH-1]; else Max =2000; float CH_output; if(FAILSAFE(CH) ==HIGH){ // If the RC channel is outside of failsafe tolerances (10-330hz and 500-2500uS) if(CH> size_RC_failsafe) CH_output =0; // and if no failsafe position has been defined, set output to neutral else CH_output =RC_failsafe[i]; // or if defined set the failsafe position } else{ // If the RC signal is valid CH_output =calibrate(PW[i],Min,Mid,Max); // calibrate the pulse width to the range -1 to 1. } return CH_output; // The signal is mapped from a pulsewidth into the range of -1 to +1, using the user defined calibrate() function in this code. // 0 represents neutral or center stick on the transmitter // 1 is full displacement of a control input is one direction (i.e full left rudder) // -1 is full displacement of the control input in the other direction (i.e. full right rudder)}/* * Receiver Calibration */ // NEED TO SPEED UPfloat calibrate(float Rx, int Min, int Mid, int Max){ float calibrated; if (Rx>=Mid) { calibrated =map(Rx, Mid, Max, 0, 1000); // map from 0% to 100% in one direction } else if (Rx ==0) { calibrated =0; // neutral } else { calibrated =map(Rx, Min, Mid, -1000, 0); // map from 0% to -100% in the other direction } return calibrated * 0.001;}// Basic Receiver FAIL SAFE// check for 500-2500us and 10-330Hz (same limits as pololu)boolean FAILSAFE(int CH){ int i =CH-1; boolean failsafe_flag =LOW; if(pwmFlag[i] ==1) // if a new pulse has been measured. { pwmFlag[i] =0; // set flag to zero if(pwmPeriod[i]> 100000) // if time between pulses indicates a pulse rate of less than 10Hz { failsafe_flag =HIGH; } else if(pwmPeriod[i] <3000) // or if time between pulses indicates a pulse rate greater than 330Hz { failsafe_flag =HIGH; } if(PW[i] <500 || PW[i]> 2500) // if pulswidth is outside of the range 500-2500ms { failsafe_flag =HIGH; } } else if (micros() - pwmTimer[i]> 100000) // if there is no new pulswidth measurement within 100ms (10hz) { failsafe_flag =HIGH; } return failsafe_flag; }/* * Quick print function of Rx channel input */void print_RCpwm(){ // display the raw RC Channel PWM Inputs for (int i =0; i =0) Serial.print(" "); if (abs(pc) <100) Serial.print(" "); if (abs(pc) <10) Serial.print(" "); Serial.print(" ");Serial.print(pc);Serial.print("% ");}/* * GENERIC PWM FUNCTIONS */unsigned long pin_time;float pin_pwm;float pin_period;boolean PWM_read(int CH){ if(CH <1 &&CH> num_ch) return false; int i =CH-1; boolean avail =pwmFlag[i]; if (avail ==HIGH){ pwmFlag[i] =LOW; noInterrupts(); pin_time =pwmTimer[i]; pin_pwm =PW[i]; pin_period =pwmPeriod[i]; 인터럽트(); } return avail;}unsigned long PWM_time(){return pin_time;}float PWM_period(){return pin_period;}float PWM(){return pin_pwm;}float PWM_freq(){ float freq; return freq =1000000 / pin_period; // frequency Hz}float PWM_duty(){ float duty; duty =pin_pwm/pin_period; return duty;}
    RC_Read_ExampleArduino
    An example sketch used to display raw data in order to calibrate your RC receiver and set your the fail safe. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
    unsigned long now; // timing variables to update data at a regular interval unsigned long rc_update;const int channels =6; // specify the number of receiver channelsfloat RC_in[channels]; // an array to store the calibrated input from receiver void setup() { setup_pwmRead(); Serial.begin(9600);}void loop() { now =millis(); if(RC_avail() || now - rc_update> 25){ // if RC data is available or 25ms has passed since last update (adjust to be equal or greater than the frame rate of receiver) rc_update =now; print_RCpwm(); // uncommment to print raw data from receiver to serial for (int i =0; i 
    RC_FrameRateArduino
    Example sketch that prints the frame rate and frequency of an RC Receiver. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
    void setup() { setup_pwmRead(); Serial.begin(9600);}void loop() { // Print RC receiver frame length and frame rate if (PWM_read(1)){ // if a new pulse is detected on channel 1 Serial.print(PWM_period(),0);Serial.print("uS "); Serial.print(PWM_freq());Serial.println("Hz"); }}
    RC_ServoMixer_ExampleArduino
    An servo mixing example. Two channels from a 6 channel are receiver are mixed and sent to two servos controlled using the servo library. The PWMread_RCfailsafe.ino file should be copied into the same folder in order for the functions to be available.
    // servo variables#include  // include the servo library to control the servosServo servo1; // name each servo output for use with the servo library Servo servo2; // Each servo must be attached to a pin that has a PWM output// on the arduino uno, nano and pro mini these pins are 3, 5, 6, 9, 10 and 11const int servo1_pin =9; // identify the pins that each servo signal wire is connected toconst int servo2_pin =10;// Select Servo Direction, Rates and Sub-trim (the size of each array must match the number of servos)boolean servo_dir[] ={0,1}; // Direction:0 is normal, 1 is reversefloat servo_rates[] ={1,0.5}; // Rates:range 0 to 2 (1 =+-500us (NORMAL), 2 =+-1000us (MAX)):The amount of servo deflection in both directionsfloat servo_subtrim[] ={0.0,0.0}; // Subtrimrange -1 to +1 (-1 =1000us, 0 =1500us, 1 =2000us):The neutral position of the servoboolean servo_mix_on =true;unsigned long now; // timing variables to update data at a regular interval unsigned long rc_update;// Receiver variablesconst int channels =6; // specify the number of receiver channelsfloat RC_in[channels]; // an array to store the calibrated input from receiver void setup() { servo1.attach(servo1_pin, 500, 2500); // attach the servo library to each servo pin, and define min and max uS values servo2.attach(servo2_pin, 500, 2500); setup_pwmRead(); Serial.begin(9600);}void loop() { now =millis(); if(RC_avail() || now - rc_update> 25){ // if RC data is available or 25ms has passed since last update (adjust to> frame rate of receiver) rc_update =now; print_RCpwm(); // uncommment to print raw data from receiver to serial for (int i =0; i 1) mix1 =1; // limit mixer output to +-1 else if(mix1 <-1) mix1 =-1; if(mix2> 1) mix2 =1; // limit mixer output to +-1 else if(mix2 <-1) mix2 =-1; // Calculate the pulse widths for the servos servo1_uS =calc_uS(mix1, 1); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) servo2_uS =calc_uS(mix2, 2); // apply the servo rates, direction and sub_trim for servo 2, and convert to a RC pulsewidth (microseconds, uS) } else{ // MIXING OFF servo1_uS =calc_uS(RC_in[1],1); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) servo2_uS =calc_uS(RC_in[2],2); // apply the servo rates, direction and sub_trim for servo 1, and convert to a RC pulsewidth (microseconds, uS) } servo1.writeMicroseconds(servo1_uS); // write the pulsewidth to the servo. servo2.writeMicroseconds(servo2_uS); // write the pulsewidth to the servo. }}int calc_uS(float cmd, int servo){ // cmd =commanded position +-100% // servo =servo num (to apply correct direction, rates and trim) int i =servo-1; float dir; if(servo_dir[i] ==0) dir =-1; else dir =1; // set the direction of servo travel cmd =1500 + (cmd*servo_rates[i]*dir + servo_subtrim[i])*500; // apply servo rates and sub trim, then convert to a uS value if(cmd> 2500) cmd =2500; // limit pulsewidth to the range 500 to 2500us else if(cmd <500) cmd =500; return cmd;}

    회로도

    This RC Receiver is powered by 5v and ground from the ICSP pins with the 6 signal outputs connected to pins 2-7
    Micro servo 1 is powered by 5v pin and ground, with signal wire connected to pin 9
    Micro servo 2 powered by 3.3v pin and ground, with signal wired connected to pin 10

    제조공정

    1. C - 입력 및 출력
    2. LCD 애니메이션 및 게임
    3. Arduino와 스마트폰을 사용한 DIY 전압계
    4. 온도 및 습도 데이터 로거
    5. DHT11로 Blynk에서 온도와 습도를 읽는 방법
    6. Python3 및 Arduino 통신
    7. Arduino 및 OLED 기반 Cellular Automata
    8. Arduino 및 RDA8057M을 사용하는 FM 라디오
    9. Arduino TEA5767 FM 라디오 수신기
    10. Arduino용 절연 아날로그 입력