<h2 id="차체-및-회로-구성" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1.25em; transition: all 0.2s ease-in-out 0s; padding-bottom: 0.5em; border-bottom: 1px solid rgb(233, 220, 190); color: #343434; background-color: #f3f3f3;">차체 및 회로 구성</h2>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">이번 프로젝트에서 사용한 차체와 회로의 구성은 이전 포스트에서와 완전히 동일합니다. 자세한 정보를 위해서는 이전 포스트인 ‘아두이노 인코더를 이용해 일정한 거리 보내기’를 참고해주세요! 아래 링크를 누르면 바로 이동합니다.</p>
<ul style="box-sizing: border-box; orphans: 3; widows: 3; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 22px; background-color: #f3f3f3;">
   <li style="box-sizing: border-box; margin-bottom: 0.5em; font-size: 1em;"><a href="https://myoungjinkim.github.io/arduino/arduino-encorder-drive/" style="box-sizing: border-box; color: #343434; transition: all 0.2s ease-in-out 0s;" target="_blank">아두이노 인코더를 이용해 일정한 거리 보내기</a></li>
   </ul>
<h2 id="똑바로-가기" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1.25em; transition: all 0.2s ease-in-out 0s; padding-bottom: 0.5em; border-bottom: 1px solid rgb(233, 220, 190); color: #343434; background-color: #f3f3f3;">똑바로 가기</h2>
<h3 id="왜-한쪽으로-휘어지는가" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1em; color: #343434; background-color: #f3f3f3;">왜 한쪽으로 휘어지는가?</h3>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">아래 그림에서 보는 것처럼 같은 PWM을 주더라도 두 모터의 회전속도가 달라서 한쪽으로 휘어집니다. 아래 그림에서는 오른쪽 바퀴에 붙인 모터 A가 항상 모터 B보다 빠르게 회전하여 차체가 왼쪽으로 휘어졌습니다.</p>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;"><img src="https://myoungjinkim.github.io/images/motor-speed-diff-at-100.png" alt="두 모터의 회전 속도 차이 측정" style="box-sizing: border-box; max-width: 100%; height: auto; vertical-align: middle; border: 0px; transition: all 0.2s ease-in-out 0s;" /></p>
<h3 id="똑바로-보내려면" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1em; color: #343434; background-color: #f3f3f3;">똑바로 보내려면?</h3>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">두 모터의 속도가 같아지도록 PWM을 조정하여야 합니다. 두 모터를 동시에 조정하는 것은 어렵기 때문에, 한쪽 모터의 회전 속도를 기준으로 다른 모터의 속도를 조절하는 것이 편리합니다.</p>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">예를 들어 왼쪽 바퀴에 연결된 모터 B를 기준으로 두고 생각해 봅시다. 모터 A가 모터 B보다 빠르게 돈다면, 모터 A에 주는 PWM을 줄여서 모터 B와 같은 속도로 만들어야 합니다. 반대로, 모터 A가 모터 B보다 느리게 돈다면, 모터 A에 주는 PWM을 높여서 모터 B와 같은 속도로 만들어야 합니다.</p>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">그런데 두 모터의 회전 속도 차이가 난다고 어느 한 쪽 모터의 PWM 값을 갑자기 높여버리면 차체가 진전하면서도 좌우로 심하게 흔들리게 됩니다.</p>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">이러한 사항을 고려하여 속도 차이가 적게 날 경우에는 PWM 값을 조금 조정하고 속도 차이가 많이 날 경우엔 PWM 값을 많이 하는 방식을 사용하여 차체의 흔들림을 줄일 수 있습니다. 이와 같은 방법을 오류에 비례하는 값으로 출력 값력 조정한다 하여 비례 제어기(proportional controller)라 부릅니다.</p>
<h3 id="비례-제어기" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1em; color: #343434; background-color: #f3f3f3;">비례 제어기</h3>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">이 프로젝트에서는 모터 B를 기준으로 모터 A의 속도를 조절하여 차량을 똑바로 보내고자 합니다. 우선, 모터 B와 모터 A의 속력 차이를 오차, 즉&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">error</code>
   라고 정의합니다. 그러면&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">error</code>
   &nbsp;값이 음수면 모터 A가 빠르다는 것을, 양수면 모터 B가 빠르다는 것을 나타내게 됩니다.</p>
<div class="highlighter-rouge" style="box-sizing: border-box; position: relative; margin-bottom: 1em; background: rgb(35, 30, 24); color: #cabcb1; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; font-size: 0.75em; line-height: 1.8; border-radius: 4px;">
   <div class="highlight" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s;">
      <pre class="highlight" style="box-sizing: border-box; orphans: 3; widows: 3; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; overflow-x: auto; transition: all 0.2s ease-in-out 0s; width: 619px; margin-top: 0px; margin-bottom: 0px; padding: 1em;">
         <code style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace;">int error = encoderB - encoderA;
</code>
         </pre>
      </div>
   </div>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">에러에 비례하여 모터 A의 PWM을 조정하는데, 어느 정도의 값으로 조정할지를 정하는 값이 비례 상수입니다. 보통 비례 제어기에 사용하는 비례 상수를&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   라고 부릅니다.</p>
<div class="highlighter-rouge" style="box-sizing: border-box; position: relative; margin-bottom: 1em; background: rgb(35, 30, 24); color: #cabcb1; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; font-size: 0.75em; line-height: 1.8; border-radius: 4px;">
   <div class="highlight" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s;">
      <pre class="highlight" style="box-sizing: border-box; orphans: 3; widows: 3; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; overflow-x: auto; transition: all 0.2s ease-in-out 0s; width: 619px; margin-top: 0px; margin-bottom: 0px; padding: 1em;">
         <code style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace;">int pwmA = (int)(pwmB + Kp * error);
</code>
         </pre>
      </div>
   </div>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">예를 들어 차체가 왼쪽으로 휘어진다고 가정해 보겠습니다. 이 상황에서는&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">error</code>
   값이 음수를 나타게 됩니다. 그러면 pwmA는 pwmB 보다 작게 되므로, 모터 A의 속도가 느려지게 됩니다. 왼쪽에 연결된 모터 B보다 오른쪽에 연결된 모터 A의 속도가 느리게 되어 차량이 똑바로 가게 됩니다.</p>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">그런데, pwmA를 조절할 때 사용하는&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   &nbsp;값은 반복된 실험을 통해 설정하여야 합니다. 먼저&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   를 1로 설정하여 차량이 움직이는 모습을 살펴봅니다. 충분히 똑바로 가지 않는다면&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   &nbsp;값을 증가시키고, 좌우로 심하게 흔들린다면&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   &nbsp;값을 줄입니다. 이와 같은 과정을 반복하여 차량이 흔들림없이 앞으로 가는 적절한&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   &nbsp;값을 선택합니다.</p>
<h2 id="코드" class="active" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1.25em; transition: all 0.2s ease-in-out 0s; padding-bottom: 0.5em; border-bottom: 1px solid rgb(233, 220, 190); color: #343434; background-color: #f3f3f3;">코드</h2>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   를 여러 값으로 바꾸어 실험해야 하기 때문에, 이동 명령에 추가하여 블루 투스를 이용해&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">Kp</code>
   값을 설정하는 명령을 추가하였습니다. 시리얼 모니터를 통해&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">s &lt;Kp 값&gt;</code>
   &nbsp;명령을 주어 값을 설정할 수 있습니다.</p>
<div class="highlighter-rouge" style="box-sizing: border-box; position: relative; margin-bottom: 1em; background: rgb(35, 30, 24); color: #cabcb1; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; font-size: 0.75em; line-height: 1.8; border-radius: 4px;">
   <div class="highlight" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s;">
      <pre class="highlight" style="box-sizing: border-box; orphans: 3; widows: 3; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; overflow-x: auto; transition: all 0.2s ease-in-out 0s; width: 619px; margin-top: 0px; margin-bottom: 0px; padding: 1em;">
         <code style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace;">void loop() {
  if (mySerial.available()) {
    char command = mySerial.read();
    if (command == 'G' || command == 'g') {
      // 움직이기 명령 처리 ...
    } else if (command = 'S' || command == 's') {
      // Kp 설정 명령 처리
      Kp = mySerial.parseFloat();
      mySerial.print("set Kp = ");
      mySerial.println(Kp);
    }
  }
}
</code>
         </pre>
      </div>
   </div>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">비례 제어기를 이용해서&nbsp;
   <code class="highlighter-rouge" style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; padding-top: 0.1rem; padding-bottom: 0.1rem; font-size: 0.8em; background: rgb(250, 250, 250); border-radius: 4px;">move()</code>
   &nbsp;함수를 다음과 같이 수정하였습니다.</p>
<div class="highlighter-rouge" style="box-sizing: border-box; position: relative; margin-bottom: 1em; background: rgb(35, 30, 24); color: #cabcb1; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; font-size: 0.75em; line-height: 1.8; border-radius: 4px;">
   <div class="highlight" style="box-sizing: border-box; transition: all 0.2s ease-in-out 0s;">
      <pre class="highlight" style="box-sizing: border-box; orphans: 3; widows: 3; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace; overflow-x: auto; transition: all 0.2s ease-in-out 0s; width: 619px; margin-top: 0px; margin-bottom: 0px; padding: 1em;">
         <code style="box-sizing: border-box; font-family: Monaco, Consolas, &quot;Lucida Console&quot;, monospace;">// 비례 상수 선언
float Kp = 0.0;
// 비례 제어기로 차량 움직이기
void move(int distance, int pwm) {
  // ...
  while (encoderB &lt;= ticksToMove) {
    int error = encoderB - encoderA;
    int pwmB = pwm;
    int pwmA = (int)(pwmB + Kp * error);
    // ....
    drive(pwmA, pwmB);
    delay(200);
  }
  // ....
}
</code>
         </pre>
      </div>
   </div>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">전체 코드는&nbsp;<a href="https://github.com/MyoungJinKim/arduino-proportional-drive/" style="box-sizing: border-box; color: #343434; transition: all 0.2s ease-in-out 0s;" target="_blank">깃허브 레포지토리</a>에서 보실 수 있습니다.</p>
<h2 id="실험-동영상" class="" style="box-sizing: border-box; margin: 2em 0px 0.5em; line-height: 1.2; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 1.25em; transition: all 0.2s ease-in-out 0s; padding-bottom: 0.5em; border-bottom: 1px solid rgb(233, 220, 190); color: #343434; background-color: #f3f3f3;">실험 동영상</h2>
<div class="fluid-width-video-wrapper" style="box-sizing: border-box; width: 619px; position: relative; padding: 348.188px 0px 0px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; font-size: 22px; background-color: #f3f3f3;"><iframe src="https://www.youtube.com/embed/Nuap1JMYq7M" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="" id="fitvid0" style="box-sizing: border-box; position: absolute; top: 0px; left: 0px; width: 619px; height: 348.188px;"></iframe></div>
<p style="box-sizing: border-box; margin-bottom: 1.3em; orphans: 3; widows: 3; transition: all 0.2s ease-in-out 0s; font-size: 22px; color: #343434; font-family: -apple-system, BlinkMacSystemFont, Roboto, &quot;Segoe UI&quot;, &quot;Helvetica Neue&quot;, &quot;Lucida Grande&quot;, Arial, sans-serif; background-color: #f3f3f3;">위 동영상과 같이 Kp 값이 7일 때 가장 똑바로 차가 움직인다는 것을 알 수 있었습니다. 하지만 중간에 오차가 생겨 좌우로 조금씩 흔들리는 것을 발견할 수 있었는데, 다음에는 이를 개선하는 방안을 찾아보려고 합니다.</p>