ブログの説明
パソコンやアンドロイドなどの情報を収集しまとめているブログです。

記事内に張られている画像はクリックすると見やすいサイズの画像が表示されるようになっています。
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。
アクセスカウンター
検索フォーム
カレンダー
10 | 2017/11 | 12
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ルンバのROIを使っての制御Ⅲ(PCと直接接続)

関連記事
ルンバのROIを使っての制御Ⅱでは、ルンバに簡単なマイコン(Arduino)を取り付けて動かしていましたが、マイコン自体がわりと高価なとの、マイコンのプログラムとPCのプログラムを作らないといけないため、面倒ですよね。
そこで、PCから直接シリアル通信で動かせるようにしたライブラリを作りました。



もちろんシリアル通信を行う為にシリアル通信インターフェースは必要です。
でも、ルンバはUART通信なので、USB接続できるUARTインターフェースとルンバに接続する為のminiDINコネクタ(7ピン)が必要ですが、両方合わせても1500円もかからないと思います。
例えばこんなものがあります。
UARTインターフェース
miniDINコネクタ


配線はiRobotR Roomba 500 Open Interface (OI) Specificationを見てください。
配布元は分かりませんが、検索すれば上位に出てくると思います。
接続はPCからインターフェースに電源供給する場合、TXとRXとGNDだけで大丈夫です。


ハードウェアの準備ができたら次はソフトウェアです。
使用するヘッダは
CRoombaControl.h
iostream
vector
の三つです。


送信データの管理はベクターで管理するようにしました。
関数側からデータがいくつ入っているのか簡単にわかりますからね。
データの送信方法はベクターに送信したい命令を追加して送信関数の引数に入れるだけです。
この命令の数値もiRobotR Roomba 500 Open Interface (OI) Specificationに記載されています。
このサンプルではバッテリ容量を取得するだけですが、数値を変更することで走行やバンパに物が当たったかどうかも取得できます。


次にデータの受信です。
受信は全てreadData関数で行います。
この関数は型でオーバーロードでき、ルンバが返してくる型と同じ型の変数を引数に入れます。
型のサイズが1byteならchar型を、2byteならshort型を指定します。
符号の有無にも気を付けてください。
サンプルのバッテリは符号なし2byteで返してくるため、unsigned shortの変数を引数に入れています。

main.cppの内容

//main.cpp
#include "CRoombaControl.h"
#include <iostream>
#include <vector>
using namespace std;

int main()
{
	CRoombaControl *Roomba = new CRoombaControl( 7 , 115200 );
	std::vector<char> sendData;
	unsigned short bat;

	//命令指定
	sendData.push_back( 128 );
	sendData.push_back( 130 );
	sendData.push_back( 142 );
	sendData.push_back( 25 );
	//命令指定

	Roomba->sendData( sendData );
	Roomba->readData( bat );
	cout <<"バッテリ容量:"<< bat << endl;


	delete Roomba;
	return 0;
}

Serial communication lib.hの内容
//Serial communication lib.h
#include <iostream>
#include <windows.h>
#include <stdio.h>
#define READ_BUFFERSYZE 1024

using namespace std;

#pragma once

class CSerialCommunication
{
	int m_port;
	unsigned long m_BaudRate;
	int m_portFlag;//ポートオープンに成功していたら

	/* シリアルポートのハンドルを格納 */
	HANDLE m_ahSerial[100];


	BOOL SerialOpenPort(const int,long);
	BOOL SerialClosePort(const int);
	BOOL SerialWriteString2(const int, const char *);

	//文字列送信用
	BOOL SerialWriteString(const int nPortNumber, const char *pszWrite , int sendSize);
	//バイナリ送信用
	BOOL SerialWriteStringBin(const int nPortNumber, unsigned char *pszWrite , int sendSize);

	unsigned long SerialReadString(const int , char *, rsize_t ,bool);

	BOOL InitDCB(const int nPortNumber , DWORD BaudRate);
	BOOL InitCommTimeOuts(const int nPortNumber);


public:
	CSerialCommunication(int portNum,unsigned long BaudRate);
	~CSerialCommunication();
	bool OpenPort();
	//文字列受信メソッド
	//第一引数 受信用バッファ
	//第二引数 受信用バッファサイズ
	//第三引数 受信バッファ使用量を表示するかどうか
	//戻り値  受信容量[byte]
	int ReadString(char *buff, rsize_t buffSize ,bool readBufferSizeView = false);
	//文字列送信用メソッド
	//第一引数 文字列のポインタ
	//第二引数 送信容量[byte]
	bool WriteString(const char *pszWrite , int sendSize);
	//バイナリ送信用メソッド
	//第一引数 バイナリ値
	//第二引数 送信容量[byte]
	bool WriteStringBin(unsigned char *pszWrite , int sendSize);
	bool ClosePort();
};

Serial communication lib.cppの内容
//Serial communication lib.cpp
#include "Serial communication lib.h"


CSerialCommunication::CSerialCommunication(int portNum,unsigned long BaudRate)
{
	m_portFlag = false;//まだポートをあけていない
	m_port = portNum;
	m_BaudRate = BaudRate;

	for( int i = 0 ; i < 100 ; i++) m_ahSerial[i] = NULL;
}
CSerialCommunication::~CSerialCommunication()
{
	if( m_portFlag )ClosePort();//ポートが空いていたら占める
}
bool CSerialCommunication::OpenPort()
{
	if( SerialOpenPort(m_port,m_BaudRate) )
	{
		m_portFlag = true;
		return true;
	}
	return false;
}
int CSerialCommunication::ReadString(char *buff , rsize_t buffSize , bool readBufferSizeView)
{
	return SerialReadString( m_port , buff , buffSize ,readBufferSizeView);
}
bool CSerialCommunication::WriteString(const char *pszWrite , int sendSize)
{
	return SerialWriteString( m_port , pszWrite , sendSize);
}
bool CSerialCommunication::ClosePort()
{
	return SerialClosePort(m_port);
}

BOOL CSerialCommunication::InitDCB(const int nPortNumber , DWORD BaudRate)
{
    DCB dcb;

    dcb.BaudRate            = BaudRate;//通信速度(初めは38400になっていた)
    dcb.fParity             = FALSE;
    dcb.Parity              = NOPARITY;
    dcb.ByteSize            = 8;
    dcb.StopBits            = ONESTOPBIT;
    dcb.fOutxCtsFlow        = FALSE;
    dcb.fOutxDsrFlow        = FALSE;
    dcb.fDtrControl         = DTR_CONTROL_ENABLE;
    dcb.fRtsControl         = RTS_CONTROL_ENABLE;
    dcb.fDsrSensitivity     = FALSE;
    dcb.fOutX               = FALSE;
    dcb.fInX                = FALSE;
    dcb.fTXContinueOnXoff   = TRUE;
    dcb.XonLim              = 2048;
    dcb.XoffLim             = 2048;
    dcb.XonChar             = 0x11;
    dcb.XoffChar            = 0x13;
    dcb.fBinary             = TRUE;
    dcb.fNull               = FALSE;
    dcb.fAbortOnError       = TRUE;
    dcb.fErrorChar          = FALSE;
    dcb.ErrorChar           = 0x00;
    dcb.EofChar             = 0x03;
    dcb.EvtChar             = 0x02;
    dcb.DCBlength           = sizeof(DCB);
    dcb.wReserved           = 0;

    if(!SetCommState(m_ahSerial[nPortNumber - 1], &dcb))
    {
        m_ahSerial[nPortNumber - 1] = NULL;
        return FALSE;
    }

    return TRUE;
}



BOOL CSerialCommunication::InitCommTimeOuts(const int nPortNumber)
{
    COMMTIMEOUTS cto;

    cto.ReadIntervalTimeout         = 500;
    cto.ReadTotalTimeoutMultiplier  = 0;
    cto.ReadTotalTimeoutConstant    = 0;
    cto.WriteTotalTimeoutMultiplier = 0;
    cto.WriteTotalTimeoutConstant   = 0;

    if(!SetCommTimeouts(m_ahSerial[nPortNumber - 1], &cto))
    {
        m_ahSerial[nPortNumber - 1] = NULL;
        return FALSE;
    }

    return TRUE;
}


BOOL CSerialCommunication::SerialOpenPort(const int nPortNumber , long BaudRate)
{
    char szSerial[256];

    if(m_ahSerial[nPortNumber - 1] != NULL)
    {
        return FALSE;
    }

	if( nPortNumber < 10) sprintf(szSerial, "COM%d", nPortNumber);
	else sprintf(szSerial, "\\\\.\\COM%d", nPortNumber);


    m_ahSerial[nPortNumber - 1] = CreateFile(
        szSerial,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
        );

    if(m_ahSerial[nPortNumber - 1] == INVALID_HANDLE_VALUE)
    {
        m_ahSerial[nPortNumber - 1] = NULL;
		MessageBox(NULL , TEXT("ファイルを作成できませんでした") ,TEXT("エラー") , MB_OK);
        return FALSE;
    }

    if(!InitDCB(nPortNumber , BaudRate))
    {
        return FALSE;
    }

    if(!InitCommTimeOuts(nPortNumber))
    {
        return FALSE;
    }

    return TRUE;
}




BOOL CSerialCommunication::SerialClosePort(const int nPortNumber)
{
    BOOL bResult;

    bResult = CloseHandle(m_ahSerial[nPortNumber - 1]);
    m_ahSerial[nPortNumber - 1] = NULL;
	
    return bResult;
}




BOOL CSerialCommunication::SerialWriteString(const int nPortNumber, const char *pszWrite , int sendSize)
{
    DWORD dwWrittenBytes;
	BOOL ret;

    ret = WriteFile(m_ahSerial[nPortNumber - 1], (char *)pszWrite, sendSize , &dwWrittenBytes, NULL);
	return ret;
}

unsigned long CSerialCommunication::SerialReadString(const int nPortNumber, char *pszRead, rsize_t size , bool readBufferSizeView = false)
{
    COMSTAT ComStat;
    DWORD   dwError;
    DWORD   dwReadBytes;
    char    szReadBuffer[READ_BUFFERSYZE];
    BOOL    bResult;

	memset(szReadBuffer, '\0', sizeof(szReadBuffer));//バッファを初期化

	ClearCommError(m_ahSerial[nPortNumber - 1], &dwError, &ComStat);//

    bResult = ReadFile(m_ahSerial[nPortNumber - 1], (char *)szReadBuffer, ComStat.cbInQue, &dwReadBytes, NULL);


	for( int i=0; i<dwReadBytes; i++ )
	{
		// 受信文字列の中に「0~9」\r, \n 以外の文字列が混じっていたら失敗
		//if( !(('0' <= szReadBuffer[i] && szReadBuffer[i] <= '9') || szReadBuffer[i] == '\r' || szReadBuffer[i] == '\n') )
		//	return FALSE;
		//printf("%c",szReadBuffer[i]);
	}
	if( bResult )
	{
	    strcpy_s(pszRead, size, szReadBuffer);
	}

	//バッファをどれくらい使っているのかを表示
	if( readBufferSizeView )printf( "バッファ容量:%0.3lf% : %d\n" , ( ((double)dwReadBytes/(double)READ_BUFFERSYZE) * 100.0 )  , dwReadBytes );

	return dwReadBytes;

}

BOOL CSerialCommunication::SerialWriteStringBin(const int nPortNumber, unsigned char *pszWrite , int sendSize)
{
    DWORD dwWrittenBytes;
	BOOL ret;

    ret = WriteFile(m_ahSerial[nPortNumber - 1], (unsigned char *)pszWrite, sendSize, &dwWrittenBytes, NULL);
	return ret;
}

bool CSerialCommunication::WriteStringBin( unsigned char *pszWrite  , int sendSize)
{
	return SerialWriteStringBin( m_port , pszWrite , sendSize);
}

CRoombaControl.hの内容
//CRoombaControl.h
#include "Serial communication lib.h"
#include <iostream>
#include <vector>

class CRoombaControl
{
	//エンディアン変換
	int convertEndian(std::vector<char> &data);
	//データ受信
	//引数は受信データを入れるベクター
	int serialRead(std::vector<char> &data , int size);

	//シリアル通信
	CSerialCommunication *m_Serial;
public:
	CRoombaControl( int PortNum , int Speed);
	~CRoombaControl();

	//データ送信
	int sendData( std::vector<char> &sendData );

	//データ受信
	//符号なし1バイト
	void readData( unsigned char &data );
	//符号あり1バイト
	void readData( char &data );
	//符号なし2バイト
	void readData( unsigned short &data );
	//符号あり2バイト
	void readData( short &data );


};

CRoombaControl.cppの内容
//CRoombaControl.cpp
#include "CRoombaControl.h"

CRoombaControl::CRoombaControl( int PortNum , int Speed)
{
	m_Serial = new CSerialCommunication( PortNum , Speed );
	m_Serial->OpenPort();
}
CRoombaControl::~CRoombaControl()
{
	m_Serial->ClosePort();
	delete m_Serial;
}


int CRoombaControl::convertEndian(std::vector<char> &data)
{
	int i;
	char *temp;//1バイトだからbool,charでも可
	//char *dataP;
	int size = data.size();
	temp = new char[ size ];

	//テンポラリにコピー
	for(i = 0 ; i < size ; i++)
	{
		temp[i] = data[i];
	}

	//テンポラリからさかさまにコピーしなおす
	for(i = 1 ; i <= size ; i++)
	{
		data[i - 1] = temp[size - i];
	}

	delete temp;

	return 0;
}

int CRoombaControl::serialRead(std::vector<char> &data , int size)
{
	int ret = 0;
	std::vector<char> readBuf(1024);//受信用のただのバッファ
	while( 1 )
	{
		ret = 0;
		ret = m_Serial->ReadString( &readBuf.at(0) , readBuf.size() );
		for( int i = 0 ; i < ret ; i++ )
		{
			data.push_back( readBuf[i] );//後ろにくっつけていく
		}
		if( data.size() >= size )
			break;
	}
	//cout << data.size() << endl;
	convertEndian( data );
	return 0;
}

int CRoombaControl::sendData( std::vector<char> &sendData )
{
	m_Serial->WriteStringBin( (unsigned char*)(void*)(&sendData.at(0)) , sendData.size() );
	return 0;
}

void CRoombaControl::readData( unsigned char &data )
{
	std::vector<char> dataBuf;
	serialRead( dataBuf , 1 );
	memcpy( &data, &dataBuf.at(0) , dataBuf.size() );
}
void CRoombaControl::readData( char &data )
{
	std::vector<char> dataBuf;
	serialRead( dataBuf , 1 );
	memcpy( &data, &dataBuf.at(0) , dataBuf.size() );
}
void CRoombaControl::readData( unsigned short &data )
{
	std::vector<char> dataBuf;
	serialRead( dataBuf , 2 );
	memcpy( &data, &dataBuf.at(0) , dataBuf.size() );
}
void CRoombaControl::readData( short &data )
{
	std::vector<char> dataBuf;
	serialRead( dataBuf , 2 );
	memcpy( &data, &dataBuf.at(0) , dataBuf.size() );
}

COMMENT

EDIT COMMENT

非公開コメント

最新トラックバック
ブロとも申請フォーム
QLOOKアクセス解析
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。