[19] UART経由でサーボモータ制御

[15] Arduino-IDEで動かしてみる(PWMドライバサンプル)」で、PWM制御を行いました。

[17] PWMでサーボモータ制御」の進化系です。
サーボモータの角度をUARTコマンドでできるようにしてみました。
PCのCOMポートからコマンド実行することができます。

1. ハードウェア構成

PWM部は「[17] PWMでサーボモータ制御」と同様です。

PA4端子と、GND,Vccをそれぞれサーボモータ「SG92R」に接続します。

SG92Rの黒線:GND
SG92Rの赤線:Vcc(5v)
SG92Rの黄線:PA4

前回同様、サーボモータに対する電源をボードから3.3Vで取得しています。
(サーボモータ側は5Vの仕様ですが、3.3Vでも動作はするため)
簡易的な処置です。通常は面倒がらずに5V電源を接続することをお勧めします。

そして、PCのCOMポートに接続するUART部は、
[5] FreeRTOS ドライバ1―SCIドライバを使う」と同様です。
UARTのTX/RX. GNDを、UART/COM変換ケーブルに接続し、PCと接続します。

IO32: H8 SCI0のRX <—> PC側のTX
IO30: H8 SCI0のTX <—> PC側のRX

注:PCとは、3.3VインターフェースのUART/COM変換ケーブルを使用してください。

bpsは115200bpsです。

2. プログラムの準備

Arduino-IDEのスケッチをは以下です。コピー&ペーストしてください。

#include <Arduino.h>
#include <FreeRTOS.h>
#include <string.h>
#include <task.h>
#include <stdlib.h>

#define SCI_CHANNEL 0
#define PWM_CHANNEL 1 // JC-Pin7
#define MIN_PULSE_WIDTH 1000
#define MAX_PULSE_WIDTH 2000

const char *msg = "Servo Control Demo\r\n";

volatile unsigned char send_cmplt = 0;
volatile unsigned char rcv_cmplt = 0;
unsigned char buffer[100];

void sci_callback(unsigned char byte, uart_event_t event);
static void vServo(void *pvParameters);

// put your setup code here, to run once:
void setup() {
  SCI_Open(SCI_CHANNEL, 115200);
  SCI_SetCallback(SCI_CHANNEL, sci_callback);

  xTaskCreate(vServo, (signed portCHAR *)"Servo", configMINIMAL_STACK_SIZE, NULL, 2, NULL);

  vTaskStartScheduler();
}

void loop() {}

static void vServo(void *pvParameters) {
  int duty_cycle = 0;
  int angle = 0;
  send_cmplt = 0;
  SCI_Write(SCI_CHANNEL, (unsigned char *)msg, strlen(msg));
  while (!send_cmplt) vTaskDelay(1);

  timer_error_code_t ret;
  ret = PWM_Open(PWM_CHANNEL);
  if (ret != TIMER_SUCCESS) {
    SCI_Write(SCI_CHANNEL, (unsigned char*)"Fail to open PWM", 16);
    while (1) {}
  }

  while (1) {
    if (rcv_cmplt) {
      switch (buffer[0]) {
        case 'p': // set pulse width (us)
          duty_cycle = atoi((const char*)&buffer[1]);
          if (duty_cycle < MIN_PULSE_WIDTH) duty_cycle = MIN_PULSE_WIDTH;
          if (duty_cycle > MAX_PULSE_WIDTH) duty_cycle = MAX_PULSE_WIDTH;
          PWM_SetPeriodAndDuty(PWM_CHANNEL, duty_cycle, 10000);
          PWM_Start(PWM_CHANNEL);
          SCI_Write(SCI_CHANNEL, (unsigned char*)"OK\n", 3);
          break;

        case 'x': // stop
          PWM_Stop(PWM_CHANNEL); // Stop PWM at CH1
          SCI_Write(SCI_CHANNEL, (unsigned char*)"STOP\n", 5);
          break;

        case 'a': // set angle
          angle = atoi((const char*)&buffer[1]);
          if (angle < 0) angle = 0;
          if (angle > 180) angle = 180;
          duty_cycle = (float)angle/180.0*(MAX_PULSE_WIDTH - MIN_PULSE_WIDTH) + MIN_PULSE_WIDTH;
          PWM_SetPeriodAndDuty(PWM_CHANNEL, duty_cycle, 10000);
          PWM_Start(PWM_CHANNEL);
          SCI_Write(SCI_CHANNEL, (unsigned char*)"OK\n", 3);
          break;
      }
      rcv_cmplt = 0;
    }
    vTaskDelay(1);
  }
}

void sci_callback(unsigned char byte, uart_event_t event) {
  static int i = 0;
  switch (event) {
    case UART_TX_COMPLETE:
      send_cmplt = 1;
      break;
    case UART_RX_CHAR:
      if (byte == '\n') {
        rcv_cmplt = 1;
        buffer[i] = '\0';
        i = 0;
      }
      else {
        buffer[i] = byte;
        i++;
      }
      break;
  }
}

ビルドします。(図が英文となっています)

2. 実行

他のサンプル同様、あらかじめE10A-USB経由でBootloader部をダウンロードし、リセット後実行をしておきます。

先ほどのプログラムをダウンロード&実行してみます。

「マイコンボードに書き込む」を選択すると、ビルドが行われ、書き込みを開始しようとします。(図は英文なので「Upload」となっています)

書き込みが終了すると、Arduino付属のシリアルモニタを立ち上げます。

Baud Rateは115200に設定してください。

この状態で、Artyボードのリセットボタンを押します。

”Servo Control Demo”と表示されます。

これで、以下コマンドが受付可能となりました。

  • p{pulse_width} (パルス幅 1000 – 2000)
    • p1500 – パルス幅を 1500usに設定します
    • p1300 – パルス幅を 1300usに設定します
  • a{angle} (角度 0 – 180)
    • a90 – サーボの角度を 90˚にします
    • a120 – サーボの角度を 120˚にします
  • x  停止します

a45と入力してみます。

サーボが45度の位置に動作しました。

シリアルモニタには”OK”と表示されました。