趣味で作ってるロボット用ソフトウェア
 All Classes Files Functions Enumerations Enumerator Friends Pages
ルンバ-PC 間のケーブル作成

ルンバとのシリアル接続は 5V の TTL 接続で行います。そのため、通常のシリアル端子とルンバを直に接続することはできません。
今回は FTDI 社の USB-Serial 変換チップ FT232RL の評価基板を用いて PC と接続するためのケーブルを作成します。ルンバの RXD, TXD, GND を接続すれば通信できます。

dot_inline_dotgraph_4.png

作成したケーブルを用い、実際に PC からルンバにコマンドを送信してケーブルの動作を確認します。まずは PC からの送信が動作するかの確認のために、ルンバに音を鳴らせてみます。

ルンバとの通信プロトコルの詳細は参考文献から確認できます。
以下は C++ と Lua 版の音を鳴らすプログラムです。

ルンバで音を鳴らせるプログラム (C++)

/*
ルンバに音を鳴らせる
*/
#include "Serial.h"
#include "delay.h"
#include <string>
#include <iostream>
using namespace hrk;
using namespace std;
int main(int argc, char *argv[])
{
static_cast<void>(argc);
static_cast<void>(argv);
const char* device = "/dev/ttyUSB0";
//const char* device = "COM17";
Serial serial;
enum { Roomba_default_baudrate = 115200 };
if (!serial.open(device, Roomba_default_baudrate)) {
cout << "Serial::open(): " << serial.what() << endl;
return 1;
}
const char full_command[] =
"\x80"
"\x84";
serial.write(full_command, sizeof(full_command) - 1);
delay_msec(100);
const char sing_command[] =
"\x8c\x0\x1\x43\x05"
"\x8d\x0";
serial.write(sing_command, sizeof(sing_command) - 1);
delay_msec(100);
const char passive_command[] =
"\x80";
serial.write(passive_command, sizeof(passive_command) - 1);
#if 0
const char power_command[] =
"\x85";
serial.write(power_command, sizeof(power_command) - 1);
#endif
return 0;
}

ルンバで音を鳴らせるプログラム (Lua)
lib/robot/example/roomba.cpp を利用します。

-- ルンバに音を鳴らせる
local serial = Serial()
local Roomba_default_baudrate = 115200
if not serial:open("/dev/ttyUSB0", Roomba_default_baudrate) then
print("Serial::open(): " .. serial:what())
return 1
end
local full_command = "\132"
serial:write(full_command, #full_command)
print(#full_command)
delay(0.1)
local sing_command = "\140\000\001\067\032" .. "\141\000"
serial:write(sing_command, #sing_command)
print(#sing_command)
delay(1.0)
local passive_command = "\128"
serial:write(passive_command, #passive_command)
print(#passive_command)

実行方法

% ./roomba sing_roomba.lua 

ここまでで、PC からルンバへの送信が確認できました。
次は、受信のテストを兼ねてルンバのバッテリー情報を取得してみます。

ルンバのバッテリー情報を取得するプログラム (C++)

/*
ルンバのバッテリー情報を取得して表示する
*/
#include "Serial.h"
#include <string>
#include <iostream>
using namespace hrk;
using namespace std;
namespace
{
bool print_charging_state(Serial& serial)
{
const char send_command[] =
"\x80"
"\x95\x01\x15";
serial.write(send_command, sizeof(send_command) - 1);
enum {
Receive_size = 1,
Timeout = 100,
};
unsigned char receive_data;
int n = serial.read(reinterpret_cast<char*>(&receive_data),
Receive_size, Timeout);
if (n != Receive_size) {
cout << "receive data failed." << endl;
return false;
}
string message;
switch (receive_data) {
case 0:
message = "0 Not charging";
break;
case 1:
message = "1 Reconditioning Charging";
break;
case 2:
message = "2 Full Charging";
break;
case 3:
message = "3 Trickle Charging";
break;
case 4:
message = "4 Waiting";
break;
case 5:
message = "5 Charging Fault Condition";
break;
default:
message = "invalid receive data.";
break;
}
cout << message << endl;
return true;
}
bool print_battery_current(Serial& serial)
{
const char send_command[] =
"\x95\x01\x17";
serial.write(send_command, sizeof(send_command) - 1);
enum {
Receive_size = 2,
Timeout = 100,
};
unsigned char receive_data[Receive_size];
int n = serial.read(reinterpret_cast<char*>(receive_data),
Receive_size, Timeout);
if (n != Receive_size) {
cout << "receive data failed." << endl;
return false;
}
short current_mili_ampere;
current_mili_ampere =
((static_cast<unsigned short>(receive_data[0]) << 8) & 0xff00) |
(receive_data[1] & 0xff);
cout << "current: " << current_mili_ampere << " [mA]" << endl;
return true;
}
bool print_battery_charge(Serial& serial)
{
const char send_command[] =
"\x95\x01\x19";
serial.write(send_command, sizeof(send_command) - 1);
enum {
Receive_size = 2,
Timeout = 100,
};
unsigned char receive_data[Receive_size];
int n = serial.read(reinterpret_cast<char*>(receive_data),
Receive_size, Timeout);
if (n != Receive_size) {
cout << "receive data failed." << endl;
return false;
}
unsigned short current_mili_ampere;
current_mili_ampere =
((static_cast<unsigned short>(receive_data[0]) << 8) & 0xff00) |
(receive_data[1] & 0xff);
cout << "current charge: " << current_mili_ampere << " [mAh]" << endl;
return true;
}
}
int main(int argc, char *argv[])
{
static_cast<void>(argc);
static_cast<void>(argv);
const char* device = "/dev/ttyUSB0";
//const char* device = "COM17";
Serial serial;
enum { Roomba_default_baudrate = 115200 };
if (!serial.open(device, Roomba_default_baudrate)) {
cout << "Serial::open(): " << serial.what() << endl;
return 1;
}
print_charging_state(serial);
print_battery_current(serial);
print_battery_charge(serial);
return 0;
}

ルンバのバッテリー情報を取得するプログラム (Lua)
lib/robot/example/roomba.cpp を利用します。

-- ルンバのバッテリー情報を取得して表示する
local serial = Serial()
local Roomba_default_baudrate = 115200
if not serial:open("/dev/ttyUSB0", Roomba_default_baudrate) then
print("Serial::open(): " .. serial:what())
return 1
end
-- !!! not implemented
local send_command = "" .. ""
-- "\x80"
-- "\x95\x01\x15";
serial:write(send_command, #send_command)
local Timeout = 100
local receive_data = connection_read(serial, 1, Timeout)
local messages = [
"0 Not charging",
"1 Reconditioning Charging",
"2 Full Charging",
"3 Trickle Charging",
"4 Waiting",
"5 Charging Fault Condition",
]
if receive_data > #messages then
print("invalid receive data.")
return 1
end
print messages[receive_data + 1]

実行方法

% ./roomba battery_state_roomba.lua 

参考文献