はじめての電子工作超入門

第54回 SORACOM Air×3GIMによるArduinoの3G通信 その2〜Arduinoで3G通信をする方法

dsc_0064

前回3GIMで実際に3G通信ができるようになったので、今回はその使い方について、実例をもとに深めてみたいと思います。

今回の電子工作レシピ

完成までの時間目安:60分
必要なパーツ

目次

  1. 3GIMでよく利用するコマンド一覧
    1. 電波強度(RSSI)の取得(getRSSI)
    2. 通信モジュールID(固有番号)の取得(getIMEI)
    3. GPS情報の取得(getLoaction/getLocation2)
    4. SIMカードのプロファイル設定(getDefaultProfile/setDefaultProfile)
    5. HTTPによるデータの取得(httpGET/httpPOST)
  2. 定期的にデータをサーバーに蓄積してみる
  3. まとめ

1. 3GIMでよく利用するコマンド一覧

3GIMには、詳しく利用方法が書かれたマニュアルと充実したサンプルスケッチが用意されています。用途によって他にもたくさん利用するコマンドはあるのですが、今回はその中でもサーバーにデータを蓄積する例などで一般的に利用することが多いコマンドについて勉強してみます。

図1 3GIM(v2.1)のマニュアル

図1 3GIM(v2.1)のマニュアル

 

電波強度(RSSI)の取得(getRSSI)

3G通信を行う上で、通信するための電波強度を取得することができます。値は常にマイナスで、下記の数値の目安になります。主に電波強度が確保されていない場合(-113)は、通信をしないなどの判定に利用できますね。

[電波強度の目安]

  • -113:アンテナが接続されていないとき
  • -112~-90:電波受信状態が悪い状況
  • -89~-51:電波受信状態が良い状況

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「check_rssi」

a3gs.getRSSI(rssi)関数が実際に電波強度を取得する部分です。戻り値が0の場合、正常に取得され、関数に渡した引数(ここではrssi)に電波強度が格納されます。

※サンプルスケッチの★部分にdelay(15000);を加えています。これは、3G通信の準備が完了する前にgetRSSI関数を走らせると、RSSIがプラス値で返るなど正常に電波強度が返ってこないため、delayを入れて3G通信準備が完了するのを待ちます。


// 3GIM(V2) sample skech -- getRSSI

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for Start Serial Monitor
 Serial.println("Ready.");

Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded.");
 delay(15000); //★通信準備が整うまで待つ
 int rssi;
 if (a3gs.getRSSI(rssi) == 0) {
 Serial.print("RSSI = ");
 Serial.print(rssi);
 Serial.println(" dBm");
 }
 }
 else
 Serial.println("Failed.");

Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

図2 電波強度の取得

図2 電波強度の取得

成功するとこのように、電波強度が表示されます。

 

 

通信モジュールID(固有番号)の取得(getIMEI)

3GIMモジュールのID(固有番号)を取得できます。このIDはモジュール単体の固有番号になるので、複数設置した場合など、どのモジュールからデータが送られてきているか判別するケースなどに利用することができます。3GIMモジュールの表面にも固有番号が記載されています(写真1)。

写真1 IMEI番号

写真1 IMEI番号

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「get_imei」

a3gs.getIMEI(imei)関数の部分が実際に固有番号を取得する部分です。


// 3GIM(V2) sample sketch -- getIMEI

#include <SoftwareSerial.h>
#include <"a3gim.h">

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for Start Serial Monitor
 Serial.println("Ready.");

 Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded.");
 char imei[a3gsIMEI_SIZE];
 if (a3gs.getIMEI(imei) == 0) {
 Serial.print("IMEI: ");
 Serial.println(imei);
 }
 }
 else
 Serial.println("Failed.");

 Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

図3 3GIMの固有番号を取得

図3 3GIMの固有番号を取得

 

GPS情報の取得(getLoaction/getLocation2)

3GIMに搭載されているGPSモジュールで位置情報を取得することができます。位置情報の取得方法は、GPSのみを利用した位置情報の取得と、3G通信の基地局情報による取得、GPSと3G通信を併用した位置情報の取得です。用意されている関数はgetLocation – 緯度経度の取得のみと、getLocation2 – 緯度経度のほかに高度や使用GPS数、品質、時刻などの詳細情報を取得できる2種類があります。

 

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「get_location」 – getLocationの場合
「ファイル」-「スケッチの例」-「a3gim」-「get_location_agps」 – getLocation2の場合

a3gs.getLocation(a3gsMPASSISTED, lat, lng)関数の部分が実際に位置情報を取得する部分です。getLocation関数の第一引数には、a3gimMPBASED(GPS+3G通信) / a3gimMPASSISTED(3G通信のみ) / a3gimMPSTANDALONE(GPSのみ)を指定することができます。

// 3GIM(V2) sample sketch -- getLocation

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)

void setup()
{
 Serial.begin(baudrate);
 delay(3000); // Wait for start serial monitor
 Serial.println("Ready.");

 Serial.print("Initializing.. ");
 if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
 Serial.println("Succeeded. It maybe takes several minutes.");
 delay(15000); //3G通信準備が整うまで待つ
 char lat[15], lng[15];
 if (a3gs.getLocation(a3gsMPASSISTED, lat, lng) == 0) {
 Serial.print("OK: ");
 Serial.print(lat);
 Serial.print(", ");
 Serial.println(lng);
 }
 else
 Serial.println("Sorry, I don't know this location.");
 }
 else
 Serial.println("Failed.");

 Serial.println("Shutdown..");
 a3gs.end();
 a3gs.shutdown();
}

void loop()
{
}

// END

 

SIMカードのプロファイル設定(getDefaultProfile/setDefaultProfile)

前回シリアルモニターでも設定した、SIMカードの通信プロファイルを設定です。APNサーバー情報、ユーザー名、パスワードを3GIMに登録することができます。一度登録されたプロファイル情報は、書き換えされるまで有効となります。

今回利用しているSORACOM AirのSIMの場合は、プロファイル設定は下記のとおりになります。

  • APNサーバー情報: soracom.io
  • ユーザー名:sora
  • パスワード:sora

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「set_defaultprofile」

a3gs.setDefaultProfile(newApn, newUser, newPassword)関数の部分がプロファイル設定をする箇所です。
※このプログラムにもサンプルスケッチから3G通信状態の準備が完了するためのウェイトを持たせるなど少し変更を加えています。


// 3GIM(V2) sample sketch -- setDefaultProfile and getDefaultProfile

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
// New profile
const char *newApn = "soracom.io";
const char *newUser = "sora";
const char *newPassword = "sora";

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");

Serial.print("Initializing.. ");
//******************************************************************
// 1.3GIMの初期設定
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded 1.");
delay(15000); // Wait for Start Serial Monitor

//******************************************************************
// 2.現在の3GIMに設定されているデフォルトのプロファイル情報を読み込み
char apn[20], user[20], password[20];
if (a3gs.getDefaultProfile(apn, user, password) == 0) {
Serial.print("Default Profile Number is ");
Serial.print(apn);
Serial.print(",");
Serial.print(user);
Serial.print(",");
Serial.println(password);
}
else{
Serial.println("Failed getDefaultProfile.");
}
//******************************************************************
// 3.新たにプロファイル情報をSORACOM AIRのものに設定する
// if (a3gs.setDefaultProfile(newApn, newUser, newPassword) == 0) {
int error_no = 0;
error_no = a3gs.setDefaultProfile("soracom.io", "sora", "sora");
if (error_no == 0) {
Serial.println("Succeed setDefaultProfile.");
}
else{
Serial.print(error_no);
Serial.println(":Failed setDefaultProfile.");
}

}
else{
Serial.println("Failed begin.");
}

Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

void loop()
{
}

// END

図4 3GIMのプロファイル設定

図4 3GIMのプロファイル設定

プロファイル設定が無事完了すると上記のような表示となります。

 

HTTPによるデータの取得(httpGET/httpPOST)

3G通信でウェブからデータを取得する関数です。Arduinoで利用する場合は、ウェブサイトを開いてみるという使い方よりも、APIにGET/POST形式でデータを送信する、という使い方がメインになると思います。ここでは、GET形式で通信するサンプルを例にしてみます。

 

サンプルスケッチの場所
「ファイル」-「スケッチの例」-「a3gim」-「http_get」

 

a3gs.httpGET(server, port, path, res, len)関数の部分が実際に通信をする箇所になります。引数には

  • server-ホスト(deviceplus.jpなど)
  • port-ポート(通常のhttp://で始まる場合は80、https://は443を指定)
  • path-パス(ドメイン以下のパス情報)
  • res-レスポンス内容(ここに結果が入る)
  • len-レスポンスの長さ(通常はa3gsMAX_RESULT_LENGTH+1で指定)

となります。

 


// 3GIM(V2) sample sketch -- httpGET

#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "www.arduino.org";
const char *path = "";
int port = 80;

char res[a3gsMAX_RESULT_LENGTH+1];
int len;

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");

Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded.");
Serial.print("httpGET() requesting.. ");
len = sizeof(res);
delay(15000); //3G通信の準備ができるまで待つ
if (a3gs.httpGET(server, port, path, res, len) == 0) {
Serial.println("OK!");
Serial.print("[");
Serial.print(res);
Serial.println("]");
}
else {
Serial.print("Can't get HTTP response from ");
Serial.println(server);
}
}
else
Serial.println("Failed.");

Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

void loop()
{
}

// END

 

図5 3GIMによるhttp通信

図5 3GIMによるhttp通信

 

正常に接続できた場合、lenで指定したサイズ分だけres変数に結果が格納されて表示されます。

 

2. 定期的にデータをサーバーに蓄積してみる

これまで学んだコマンドをまとめて、定期的にサーバーにデータを送信して蓄積するプログラムを書いてみます。サーバー側のプログラムに関しては、次回説明するとして、Arduino側の3GIMのプログラムは下記のようになります。

このプログラムでは、RSSI、IMEI、現時刻、GPS情報などを取得して、指定したURLにGET形式でデータを送信しています。最初に、RSSIで電波強度が確認できない場合は、再度設定をやり直すようにしています。


#include <SoftwareSerial.h>
#include "a3gim.h"

#define baudrate 9600UL
const int powerPin = 7; // 3gim power pin(If not using power control, 0 is set.)
const char *server = "deviceplus.jp"; //接続先のドメイン
const char *path = "";
int port = 80;

char res[a3gsMAX_RESULT_LENGTH+1];
int len;

String imei = "";
int rssi = 0;
float lat = 0;
float lng = 0;
int height = 0;
int utc = 0;
int number = 0;
int quality = 0;
String date = "";

void setup()
{
Serial.begin(baudrate);
delay(3000); // Wait for Start Serial Monitor
Serial.println("Ready.");
}

void loop()
{
Serial.print("Initializing.. ");
if (a3gs.start(powerPin) == 0 && a3gs.begin(0, baudrate) == 0) {
Serial.println("Succeeded.");

delay(25000); // ウェイトを持たせる
Serial.println("httpGET() requesting.. ");
len = sizeof(res);

//***************************************************
//get rssi
//***************************************************
if (a3gs.getRSSI(rssi) == 0) {
Serial.print("RSSI = ");
Serial.println(rssi);
if(rssi < 0 || rssi <= -113 ){
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return 0;
}
}
else{
//電波強度が取得できない場合は最初から
Serial.println("retry.");
return 0;
}

//***************************************************
//get imei
//***************************************************
char imei[a3gsIMEI_SIZE];
if (a3gs.getIMEI(imei) == 0) {
Serial.print("IMEI: ");
Serial.println(imei);
}
//***************************************************
//get time
//***************************************************
char date[a3gsDATE_SIZE], time[a3gsTIME_SIZE];
if (a3gs.getTime(date, time) == 0) {
Serial.print("DATE:");
Serial.print(date);
Serial.print(" ");
Serial.println(time);
}

//***************************************************
//GPS-location
//***************************************************
setupAGPS();
char lat[15], lng[15], utc[7], height[8];
if (a3gs.getLocation2(lat, lng, height, utc, &quality, &number) == 0) {
Serial.print("OK: ");
Serial.print(lat);
Serial.print(",");
Serial.print(lng);
Serial.print(",");
Serial.print(height);
Serial.print(",");
Serial.print(utc);
Serial.print(",");
Serial.print(quality);
Serial.print(",");
Serial.println(number);
}

 String pathStr = "/api.php?imei=";
 String imeiS = String(imei);
 String rssiS = String(rssi);
 String latS = String(lat);
 String lngS = String(lng);
 String utcS = String(utc);
 String qualityS = String(quality);
 String numberS = String(number);
 String heightS = String(height);
 String dateS = String(date);
 String timeS = String(time);

 pathStr = pathStr+imeiS+"&rssi="+rssiS+"&utc="+utcS+"&lat="+latS+"&lng="+lngS+"&quality="+qualityS+"&number="+numberS+"&height="+height+"&datetime="+dateS+" "+timeS;

 int rst = a3gs.httpGET(server, port, pathStr.c_str(), res, len);

Serial.print("RESULT:");
Serial.println(rst);
if (rst == 0) {
Serial.println("OK!");
Serial.print("[");
Serial.print(res);
Serial.println("]");
}
else {
Serial.print("Can't get HTTP response from ");
Serial.println(server);
}
}
else{
Serial.println("Failed.");
}
Serial.println("Shutdown..");
a3gs.end();
a3gs.shutdown();
}

// setup AGPS function
void setupAGPS()
{
char apn[20], user[20], password[20];
if (a3gs.getDefaultProfile(apn, user, password) == 0) {
char atwppp[50];
sprintf(atwppp,"at+wppp=2,4,\"%s\",\"%s\"",user,password);
Serial.println(atwppp);
a3gs.enterAT(2);
a3gSerial.println(atwppp);
delay(200);
Serial.println("Assisted GPS set OK");
}
else
Serial.println("NG: getDefaultProfile(), can't use AGPS..");
}

// END

図6 サーバーに蓄積されたデータ

図6 サーバーに蓄積されたデータ

 

まずはこれで、サーバーにデータをためれるようになりました!

まとめ

サーバーにデータがためられる環境ができましたので、次回からはセンサ評価キットやほかのセンサなどを拡張させて、スタンドアローンで動作するデータロガーを作成してみたいと思います。

 

■関連記事

SORACOM Air×3GIMによるArduinoの3G通信〜Arduinoで3G通信をする方法(2)
SORACOM Airを使ってArduinoで通信できる?~Arduinoで3G通信をする方法(1)
ラズベリーパイとSORACOM Airでインターネット接続!(1)登録編

ゼロから作るライントレーサー
赤川シホロ

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。