同じスケッチがArduino互換ボードではうまくいかない

状況

キー入力に応じてHSPで一文字シリアル送信してArduinoで受信し文字に応じてあらかじめ割り振っておいた動作を行う。
要はPCのキー入力でArduinoに接続したモータドライバを操作するというもの。
純正ArduinoUNOでは問題なく動作するのに、ArduinoMega互換ボードではうまく通信できない。
当然同じスケッチ、同じプログラムである。
さらに、送信文字はただの文字列型の数字ひとつのため、
ArduinoIDEのシリアルモニタでも動作は確認できる。
これが、UNOは当然ながら、Mega互換ボードでも正常に動作してしまうのである。

つまり、
全く同じプログラムを使っても、
UNOとシリアルモニタ、
UNOとHSP
Megaとシリアルモニタ、
MegaとHSPの組み合わせのうち、
MegaとHSPの場合のみ不具合が発生する。

HSP側プログラム

#include "hspext.as"
	count=0
	//アクション生成
	up=0
	down=0
	left=0
	right=0
	action=0
	
	comopen 4,"baud=9600 parity=N data=8 stop=1"  //ボーレート9600、パリティなし、データビット8、ストップビット1
	ok=stat
	if ok==0 {
		mes "connection successful \n"
	}else{ 
		mes "connection failed \n" 
	}

//キー情報取得とコマンド生成
*checkey	
	getkey up,38
	if up==1 {
		action=action+3
		//comput "1"	//action変数の値をシリアル送信
		//:goto *serv
	}
	
	getkey down,40
	if down==1{
		action=action+6
		//comput "2"	//action変数の値をシリアル送信
		//:goto *serv
	}
	
	getkey left,37
	if left==1{
		action=action+4
		//comput "3"	//action変数の値をシリアル送信
		//:goto *serv
	}
	
	getkey right,39
	if right==1{
		action=action+5
		//comput "4"	//action変数の値をシリアル送信
		//:goto *serv
	}
	goto *serv

//キー入力に対してコマンド送信
*serv
	switch action               ; actionを比較対象とする
	case 3                 ; aが1だった場合
		comput "3"
		swbreak
	case 7                 ; aが1だった場合
		comput "7"
		swbreak	
	case 8                ; aが1だった場合
		comput "8"
		swbreak
	case 4                ; aが1だった場合
		comput "4"
		swbreak
	case 5                 ; aが1だった場合
		comput "5"
		swbreak
	case 6                 ; aが1だった場合
		comput "6"
		swbreak
	case 10                 ; aが1だった場合
		comput "1"
		swbreak
	case 11                ; aが1だった場合
		comput "2"
		swbreak		
	default                ; aが0以外だった場合
		comput "0"
		swbreak
	swend
	
	serve=stat	//送信の成否を読み込み
	if serve==1 {
		mes "success \n"+action
	}else{
		mes "failed \n"
	}
	wait 10   //ここが送信の可否に関わる
	action=0
	if(count>=12){
		cls
		count=0
	}else{
		count++
	}
	goto *checkey 

こういう具合に、十字キー、もとい凸字キーが押されたときに変数actionにそれぞれ3,4,5,6が足されるようにしておくことで、数字が被ることなく同時押しを含めた動作を表現している。

二進数でやれよという声が聞こえてきそうだが、最初に思いついたのがこれだったから仕方ない。操作ポート数を増やしたタイプのプログラムも作っているが、そちらは二進数でキー入力を扱っている。

そして、作られた数値に応じてシリアルポートに一文字送信する。

Arduino側スケッチ

#define M1A 2
#define M1B 4
#define M2A 7
#define M2B 8

void setup(){
  // シリアルポートを9600 bps[ビット/秒]で初期化
  Serial.begin(9600);
  pinMode(2,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  pinMode(11,OUTPUT); 
  pinMode(12,OUTPUT);
  /*
        digitalWrite(7,HIGH);
        digitalWrite(6,HIGH);
        digitalWrite(5,HIGH);
        digitalWrite(4,HIGH);
  */
}
 
void loop(){
  digitalWrite(6,HIGH);
  digitalWrite(12,HIGH);
  digitalWrite(9,HIGH);
  digitalWrite(10,HIGH);
  int input;
  // シリアルポートより1文字読み込む
  input = Serial.read();
  
  if(input != -1 ){
    // 受け取った文字を送信
    Serial.write(input);
    Serial.write("\n");
    switch(input){
      case '0':
        Serial.write("N!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,LOW);
        break;
     case '3':
        Serial.write("F!");
        digitalWrite(M1A,HIGH);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,HIGH);
        digitalWrite(M2B,LOW);
        break;
      case '7':
        Serial.write("LF!");
        digitalWrite(M1A,HIGH);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,LOW);
        break;       
      case '8':
        Serial.write("RF!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,HIGH);
        digitalWrite(M2B,LOW);
        break;
      case '4':
        Serial.write("left!");
        digitalWrite(M1A,HIGH);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,HIGH);
        break;      
     case '5':
        Serial.write("right!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,HIGH);
        digitalWrite(M2A,HIGH);
        digitalWrite(M2B,LOW);
        break;
      case '6':
        Serial.write("Rev!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,HIGH);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,HIGH);
        break;
      case '1':  
        Serial.write("LR!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,HIGH);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,LOW);
        break;
      case '2':  
        Serial.write("RR!");
        digitalWrite(M1A,LOW);
        digitalWrite(M1B,LOW);
        digitalWrite(M2A,LOW);
        digitalWrite(M2B,HIGH);
        break;
      default:/*
        Serial.write("N!");
        digitalWrite(4,LOW);
        digitalWrite(7,LOW);
        digitalWrite(6,LOW);
        digitalWrite(5,LOW);
        */
        break;
    }
  }
}

一文字受け取ってモータドライバのピンに信号を送る。
こんな感じなのでシリアルモニタでも動作は確認できる。
これで上記の条件でのみ通信ができないときている。全くわけが分からない。

通信不良の原因?

しばらくお手上げ状態だったが、ある日、HSP側のweitのところを変えたらどうか、と考えた。weitは10にしてある、weit 1 は10msの停止のため、現状でも0.1秒も待ってやっているのだ。ここをweit 100、つまり一秒かましてやったところ通信に成功した。さすがにナメすぎか…と50にしてみると反応しない。少しづつ待ち時間を増やしていくと、weit 90から反応しはじめた。
これではロボットを操作してもレスポンスが悪すぎて話にならない。

HSPのプログラムの場合はweit時間待ったら即、次のデータを送るため、バッファのデータを処理し終わる前に次のが来てしまうため通信がうまくいかないのだろうという結論を出した。
シリアルモニタの場合にうまくいったのは一回しか送信しないためだろう。

Arduino互換ボードはUSB-シリアル変換チップに安価なCH340とかいうのを使っているという話だがそれの関係なのか?
にしても一秒待たなくてはいけないのは異常すぎる気もするし、結局よくわからない。

2018/10/27追記
やる気を失って放置していたがちょっときっかけがあったのでシリアル変換チップを介さずにシリアル通信できる方法として、RN42のシールドを使ってBluetooth経由でシリアル通信してみた。
結果、速度の問題は解決した。
実際、ロボットを操作するときにはこれを使おうと思っていたので結果オーライか。