プチロボ2PIC搭載ボード制御ソフトのシリアル通信用のダミーコードを作ってみた

###はじめに

共立プロダクツのプチロボ制御ソフトは、Windows版しか提供されていません。そこで、Linuxでも操作できるようにしてみたかったので、コントロールボードとPC間のシリアル通信をするための準備のためにC言語でのシリアル通信コードの学習もかねて簡単なソフトウェアを作ってみた。

###コントロールボードについて

サーボモータを最大20個も操作できます。また、A/D入力にも対応しており、デジタル出力用のピンも出ています。サーボモータ用の操作には、I2C通信を使うケースが多く、シリアル通信での制御はあまり見かけません。せっかく手元にある玩具なので、もう少し深く楽しんでみたくなったのですが、はじめから準備されたWindowsソフトで遊ぶだけでは物足りません。

「WR-MSXX」の通信プロトコルは、共立電子の専用サイトからダウンロードが可能です。
https://drive.google.com/open?id=1lnpenY3FXI092F3Dacd8IQRRztPIJDvg

ZIPファイルをダウンロードして、解凍したフォルダのtutorial > pdffiles とたどると、ハードウェアマニュアルのPDFが無料で提供されています。（wr-xx_hardware2.pdf）更に、ハードウェアの回路図があります。PICが２個使われています。

・PIC16F687
・PIC16F886

PIC16F687がFT232RL経由でPCにつながります。２つのPIC間は、I2C通信設定のようです。以前から、Raspberry PiとPICとの組みあせには興味があったのですが、まさに、その実験にうってつけの製品だと思いました。

###C言語でのシリアル通信コードについて
特に役に立ったのは、そのものズバリ、「The Linux Serial Programming HOWTO」（日本語版）です。
http://linuxjf.osdn.jp/JFdocs/Serial-Programming-HOWTO.html

###ダミーコード・サンプル

いろいろとわからないことが多かったものの、結果的には簡単なコードになりましたので、全文を掲載します。結局、シリアル通信に使用するデバイスドライバファイルの扱いは、K＆Rの「プログラミング言語Ｃ」の第8章2節の「低水準入出力ーーReadとWrite」の解説がとても役にたちましたが、それ以外は、「Ｃの絵本」を片手に学習したものです。

```c:my_ttyUSB0.c
/***********************************************************************************************************
 * サンプルプログラム（Linux版 WR-XX返信ダミープログラム）無限ループ
 * Lian Ivvakanni (12-19-2020)
 * プログラムの内容
 * 　・Wonder Roid Motion Maker V343.1.1からのA/D入力取得コマンド（コマンド 5）を受信して
 * 　　WM:Wait data stack Memory状態「空」(=0)を送信する
 * WR-XX 通信プロトコルガイド（第2版）仕様
 * RS232C 通信設定（半二重通信）
 * 　・通信速度　　　　　　　　　　：38400bps
 * 　・データ形式　　　　　　　　　：バイナリーモード出力
 * 　・データ　　　　　　　　　　　：8ビット
 * 　・ストップビット　　　　　　　：1
 * 　・パリティ　　　　　　　　　　：無し
 * 　・ハンドシェイク（フロー制御）：無し
 * 　・シリアルポート　　　　　　　：/dev/ttyUSB0
 * 
***********************************************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define MODEM_DEVICE "/dev/ttyUSB0"
#define BAUD_RATE   B38400
#define N 255

int main(int argc, char *argv[])
{
    int  fd, i, rlen, slen;
    struct termios tio;
    char s[8], rBuf[N] = {'\0'}, sBuf[N] = {'\0'};

    // WMデータ
    unsigned long mwData[] = {0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x00}; 
    // AD入力取得コマンド（コマンド 5）
    unsigned long cmd_five[] = {0xFD,0x04,0x05,0xFE};

    memset(&tio, 0, sizeof(tio));
    tio.c_cflag = BAUD_RATE | CS8 | CLOCAL | CREAD;
    tio.c_cc[VTIME] = 0; // キャラクタ間タイマは未使用
    tio.c_cc[VMIN] = 0;  // 文字受け取りブロックなし 

    // サーボ制御出力コマンド（ヘッダ）
    slen = sizeof(mwData) / sizeof(mwData[0]);
    sBuf[0] = 0xFD;
    sBuf[1] = slen + 4;
    sBuf[2] = 0x15; //
    sBuf[slen + 3] = 0xFE; 

    for (i = 3; i < slen; i++) {
        sBuf[i] = mwData[i-2];
    }
    /* 出力データのデバッグ
    for (i = 0; i < slen + 4; i++){
        printf("%02X ", sBuf[i]);
    } 
    printf("\n");
    */
    fd = open(MODEM_DEVICE, O_RDWR);
    if (fd < 0) {
        perror(MODEM_DEVICE);
        exit(-1);
    }
    tcflush(fd, TCIFLUSH);
    ioctl(fd, TCSETS, &tio);

    while(1){
        rlen = read(fd,rBuf, sizeof(rBuf));
        if(rlen < 0)
            printf("Device Read Error...\n");
        if(rlen == 0)
            continue;
        else if(rBuf[1] == cmd_five[1] && rBuf[2] == cmd_five[2]){
            // デバイスへ書き込み
            write(fd, sBuf, 15);
        } else {
            for(i = 0;i < rlen; i++){
                    sprintf(s,"%02X", rBuf[i]);
                    printf("%s ",s);
            }
            printf("\r\n");
        }
        rlen = 0;
    }
    close(fd);
    return 0;
}
```

### おわりに

たったこれだけのことを理解するために、2週間ほどかかりました。やはり、独学というのは時間がかかって大変ですが、ある程度理解できたときの喜びもひとしおです。

これから、操作コマンドの送信用のプログラムはできていませんが、シリアル通信でサーボモータのコントロールは、結構大変そうです。UARTは、基本的な通信方式なので、ぜひとも基本的な仕組みは知っておきたかったので、もう少し学習をつづけておきたいと思います。