はじめに
はじめまして!
もともとラズベリーパイ、Arduinoを使った電子工作モノが好きなyochanと申します。
SONY製評価ボードSPRESENSEの良さを感じたいと調べていましたところ自然とポチってしまいました。
他の評価ボードには標準でないものがメインボードに載ってたりして、SONYのロゴが入っているところも個人的に好きなポイントです。
そんなわけで初めての開発になりますが、これあると便利じゃないか?というものを趣味レベルでチャレンジしたいと思います。
解決したい課題
大きなショッピングモールで自分が駐車した車の駐車場所を忘れた・・・
こんなことってありませんか?忘れない人と、忘れる人、様々いらしていると思いますが私はよく忘れてしまいます。
ここに停めたぞ!と意気込んでいても帰るころにはさっぱり。大きめの駐車場でこの現象に遭遇すると、探し当てるのにとても時間がかかってしまいますよね。探し当てた時の喜びはありますが、それまでの時間コストのがはるかに大きいです。
さらに、重たい荷物を持ったまま探すとなるとそれにかける労力は大きいと私は考えます。
解決策
車に置いたままのGPSモジュール内蔵のSPRESENSEがGPS信号を受信し、
緯度と経度情報をBLEモジュールから送信し、
Webアプリ上で確認できるシステムを作ります。
##準備物
部品 | 個数 | 概要 | 費用 |
---|---|---|---|
SPRESENSEメインボード | 1 | Arduino 互換 ボードコンピュータ | 6,800円 |
BLE1507 | 1 | SPRESENSEにBluetooth LEを接続するための拡張キットボード | 3,850円 |
電源降圧モジュール | 1 | 乾電池9Vの電源を降圧させるモジュール基板 | 635円 |
LED電圧計 | 1 | 定格電圧にならないように常時監視用のLED電圧計 | 899円 |
電池クリップ | 1 | 9V乾電池からスイッチまでの配線用クリップ | 690円 |
ロッカースイッチ | 1 | 電源のスイッチに利用 | 635円 |
LTE拡張をしてしまうとSIM利用料が必要になるため、BLE1507を使うことにしました。
またメインボードが小さいのをメリットにしておきたいということも考慮し、拡張ボードは今回使いませんでした。
合計:13,509円です。
BLE1507の取付け
合体させました!
BLE1507のCN1がSPRESENSEのGND、CN2の2ピンがSPRESENSEの2ピン目の1.8Vにつながるように接続します。
丁寧にピンソケットに挿入してあげないと、BLE1507のピンが曲がりかけたので慎重にまっすぐを意識!
メインボードからはみ出ないのがやっぱりスッキリ見えます!
電源
自動車内に置いて使用する場合は電源をバッテリー駆動する必要があります。(本当はUSB給電できたらいいんですが・・・)
SPRESENSEメインボードへの最大絶対定格電圧は5.5Vらしいですが手持ちのものでは供給できなかったため、
9Vを降圧させて電源をオンオフするためのスイッチを取り付けました。
プログラム
Arduinoを開発環境としました。
BLE1507はSONYのSpresense SDK Libraryを使用しました。
GPSはGNSSのサンプルコードを使用しています。リソース上、余裕があるので使用しない関数はそのままにしています。
GPSの緯度、経度情報をシリアル通信で出力する箇所はデバッグ用途で記述しています。
BLE_gps_main.inoは主にメインの処理、ble_main.ino、gps_main.inoは各機能をもった関数ごとにファイルを分けています。
※BLEの基本通信仕様のご説明は割愛させていただきますが、
PeripheralをSpresense、BLE CentralをWebアプリとして構築しています。
BLE_gps_main.ino
/*
BLE peripheral
*/
/****************************************************************************
Included Files
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <bluetooth/ble_gatt.h>
/* include the GNSS library */
#include <GNSS.h>
#define STRING_BUFFER_SIZE 128 /**< %Buffer size */
#define RESTART_CYCLE (60 * 5) /**< positioning test term */
SpGnss Gnss; /**< SpGnss object */
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <bluetooth/ble_gatt.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define BLE_UUID_SDS_SERVICE_IN 0x3802
#define BLE_UUID_SDS_CHAR_IN 0x4a02
#define BONDINFO_FILENAME "/mnt/spif/BONDINFO"
/****************************************************************************
* Function Prototypes BLE
****************************************************************************/
/* BLE common callbacks */
/* Connection status change */
void onLeConnectStatusChanged(struct ble_state_s *ble_state,
bool connected, uint8_t reason);
/* Device name change */
void onConnectedDeviceNameResp(const char *name);
/* Save bonding information */
void onSaveBondInfo(int num, struct ble_bondinfo_s *bond);
/* Load bonding information */
int onLoadBondInfo(int num, struct ble_bondinfo_s *bond);
/* Negotiated MTU size */
void onMtuSize(uint16_t handle, uint16_t sz);
/* Encryption result */
void onEncryptionResult(uint16_t, bool result);
/* BLE GATT callbacks */
/* Write request */
void onWrite(struct ble_gatt_char_s *ble_gatt_char);
/* Read request */
void onRead(struct ble_gatt_char_s *ble_gatt_char);
/* Notify request */
void onNotify(struct ble_gatt_char_s *ble_gatt_char, bool enable);
/* BLE GATT callbacks */
/* Write request */
void onWrite(struct ble_gatt_char_s *ble_gatt_char);
/* Read request */
void onRead(struct ble_gatt_char_s *ble_gatt_char);
/* Notify request */
void onNotify(struct ble_gatt_char_s *ble_gatt_char, bool enable);
int g_ble_bonded_device_num;
struct ble_cccd_s **g_cccd = NULL;
bool ble_is_notify_enabled = false;
uint16_t ble_conn_handle;
char local_ble_name[BT_NAME_LEN] = "SPR-PERIPHERAL";
BT_ADDR local_addr = {{0x19, 0x84, 0x06, 0x14, 0xAB, 0xCD}};
struct ble_gatt_service_s *g_ble_gatt_service;
struct ble_common_ops_s ble_common_ops =
{
.connect_status_changed = onLeConnectStatusChanged,
.connected_device_name_resp = onConnectedDeviceNameResp,
.mtusize = onMtuSize,
.save_bondinfo = onSaveBondInfo,
.load_bondinfo = onLoadBondInfo,
.encryption_result = onEncryptionResult,
};
static BLE_CHAR_VALUE char_value =
{
.length = BLE_MAX_CHAR_SIZE
};
static BLE_CHAR_PROP char_property =
{
.read = 1,
.write = 1,
.notify = 1
};
static uint8_t char_data[BLE_MAX_CHAR_SIZE];
static BLE_ATTR_PERM attr_param =
{
.readPerm = BLE_SEC_MODE1LV2_NO_MITM_ENC,
.writePerm = BLE_SEC_MODE1LV2_NO_MITM_ENC
};
struct ble_gatt_peripheral_ops_s ble_gatt_peripheral_ops =
{
.write = onWrite,
.read = onRead,
.notify = onNotify
};
struct ble_gatt_char_s g_ble_gatt_char =
{
.handle = 0,
.ble_gatt_peripheral_ops = &ble_gatt_peripheral_ops
};
/****************************************************************************
Pre-processor Definitions GNSS
****************************************************************************/
#define BLE_UUID_SDS_SERVICE_IN 0x3802
#define BLE_UUID_SDS_CHAR_IN 0x4a02
#define BONDINFO_FILENAME "/mnt/spif/BONDINFO"
void ble_settings();
void Led_isActive();
void Led_isPosfix(bool state);
void print_pos(SpNavData *pNavData);
void print_condition(SpNavData *pNavData);
void setup_start_led_driver();
void setup_gnss(int begin_message);
void setup_gnss_cold_start(int begin_message);
void setup_done_led_driver();
void setup() {
/* put your setup code here, to run once: */
int error_flag = 0;
/* Set serial baudrate. */
Serial.begin(115200);
/* Wait HW initialization done. */
sleep(3);
/* Turn on all LED:Setup start. */
setup_start_led_driver();
/* Set Debug mode to Info */
Gnss.setDebugMode(PrintInfo);
/* Activate GNSS device */
int result;
result = Gnss.begin();
setup_gnss(result);
/* Start positioning */
result = Gnss.start(COLD_START);
setup_gnss_cold_start(result);
setup_done_led_driver();
int ret = 0;
BLE_UUID *s_uuid;
BLE_UUID *c_uuid;
/* Initialize BT HAL */
ret = bt_init();
if (ret != BT_SUCCESS)
{
printf("%s [BT] Initialization failed. ret = %d\n", __func__, ret);
goto error;
}
/* Register BLE common callbacks */
ret = ble_register_common_cb(&ble_common_ops);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Register common call back failed. ret = %d\n", __func__, ret);
goto error;
}
/* Turn ON BT */
ret = bt_enable();
if (ret != BT_SUCCESS)
{
printf("%s [BT] Enabling failed. ret = %d\n", __func__, ret);
goto error;
}
/* Free memory that is allocated in onLoadBond() callback function. */
free_cccd();
/* BLE set name */
ret = ble_set_name(local_ble_name);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Set name failed. ret = %d\n", __func__, ret);
goto error;
}
/* BLE set address */
ret = ble_set_address(&local_addr);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Set address failed. ret = %d\n", __func__, ret);
goto error;
}
/* BLE enable */
ret = ble_enable();
if (ret != BT_SUCCESS)
{ printf("%s [BLE] Enable failed. ret = %d\n", __func__, ret);
goto error;
}
/* BLE create GATT service instance */
ret = ble_create_service(&g_ble_gatt_service);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Create GATT service failed. ret = %d\n", __func__, ret);
goto error;
}
/* Setup Service */
/* Get Service UUID pointer */
s_uuid = &g_ble_gatt_service->uuid;
/* Setup Service UUID */
s_uuid->type = BLE_UUID_TYPE_BASEALIAS_BTSIG;
s_uuid->value.alias.uuidAlias = BLE_UUID_SDS_SERVICE_IN;
/* Setup Characteristic */
/* Get Characteristic UUID pointer */
c_uuid = &g_ble_gatt_char.uuid;
/* Setup Characteristic UUID */
c_uuid->type =BLE_UUID_TYPE_BASEALIAS_BTSIG;
c_uuid->value.alias.uuidAlias = BLE_UUID_SDS_CHAR_IN;
/* Set data point */
char_value.data = char_data;
/* Setup Characteristic BLE_ATTR_PERM */
memcpy(&char_value.attrPerm, &attr_param, sizeof(BLE_ATTR_PERM));
/* Setup Characteristic BLE_CHAR_VALUE */
memcpy(&g_ble_gatt_char.value, &char_value, sizeof(BLE_CHAR_VALUE));
/* Setup Characteristic BLE_CHAR_PROP */
memcpy(&g_ble_gatt_char.property, &char_property, sizeof(BLE_CHAR_PROP));
/* BLE add GATT characteristic into service */
ret = ble_add_characteristic(g_ble_gatt_service, &g_ble_gatt_char);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Add GATT characteristic failed. ret = %d\n", __func__, ret);
goto error;
}
/* BLE register GATT service */
ret = ble_register_servce(g_ble_gatt_service);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Register GATT service failed. ret = %d\n", __func__, ret);
goto error;
}
/* BLE start advertise */
ret = ble_start_advertise();
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Start advertise failed. ret = %d\n", __func__, ret);
goto error;
}
return ret;
error:
return ret;
}
void loop() {
/* put your main code here, to run repeatedly: */
static int LoopCount = 0;
static int LastPrintMin = 0;
static int ret = 0;
static uint8_t data[BLE_MAX_CHAR_SIZE];
static uint8_t ble_notify_data = 0;
static int len;
/* Blink LED. */
Led_isActive();
/* Check update. */
if (Gnss.waitUpdate(-1))
{
/* Get NaviData. */
SpNavData NavData;
Gnss.getNavData(&NavData);
/* Set posfix LED. */
bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
Led_isPosfix(LedSet);
// Get the location
float lat = (float)NavData.latitude;
float lon = (float)NavData.longitude;
/* Print position information. */
print_pos(&NavData);
sprintf(data, "%.6f,%.6f", lat, lon);
if (ble_is_notify_enabled)
{
ret = ble_characteristic_notify(ble_conn_handle,
&g_ble_gatt_char,
data,
BLE_MAX_CHAR_SIZE);
if (ret != BT_SUCCESS)
{
printf("%s [BLE] Send data failed. ret = %d\n", __func__, ret);
}
}
sleep(1);
return ret;
}
/* Check loop count. */
LoopCount++;
if (LoopCount >= RESTART_CYCLE)
{
int error_flag = 0;
/* Turn off LED0 */
ledOff(PIN_LED0);
/* Set posfix LED. */
Led_isPosfix(false);
/* Restart GNSS. */
if (Gnss.stop() != 0)
{
Serial.println("Gnss stop error!!");
error_flag = 1;
}
else if (Gnss.end() != 0)
{
Serial.println("Gnss end error!!");
error_flag = 1;
}
else
{
Serial.println("Gnss stop OK.");
}
if (Gnss.begin() != 0)
{
Serial.println("Gnss begin error!!");
error_flag = 1;
}
else if (Gnss.start(HOT_START) != 0)
{
Serial.println("Gnss start error!!");
error_flag = 1;
}
else
{
Serial.println("Gnss restart OK.");
}
LoopCount = 0;
/* Set error LED. */
if (error_flag == 1)
{
Led_isError(true);
exit(0);
}
}
return ret;
}
ble_main.ino
/*
* BLE function
*
*/
/****************************************************************************
* Private Functions
****************************************************************************/
void onLeConnectStatusChanged(struct ble_state_s *ble_state,
bool connected, uint8_t reason)
{
BT_ADDR addr = ble_state->bt_target_addr;
/* If receive connected status data, this function will call. */
printf("[BLE_GATT] Connect status ADDR:%02X:%02X:%02X:%02X:%02X:%02X, status:%s, reason:%d\n",
addr.address[5], addr.address[4], addr.address[3],
addr.address[2], addr.address[1], addr.address[0],
connected ? "Connected" : "Disconnected", reason);
ble_conn_handle = ble_state->ble_connect_handle;
}
void onConnectedDeviceNameResp(const char *name)
{
/* If receive connected device name data, this function will call. */
printf("%s [BLE] Receive connected device name = %s\n", __func__, name);
}
void onSaveBondInfo(int num, struct ble_bondinfo_s *bond)
{
int i;
FILE *fp;
int sz;
/* In this example, save the parameter `num` and each members of
* the parameter `bond` in order to the file.
*/
fp = fopen(BONDINFO_FILENAME, "wb");
if (fp == NULL)
{
printf("Error: could not create file %s\n", BONDINFO_FILENAME);
return;
}
fwrite(&num, 1, sizeof(int), fp);
for (i = 0; i < num; i++)
{
fwrite(&bond[i], 1, sizeof(struct ble_bondinfo_s), fp);
/* Because only cccd is pointer member, save it individually. */
sz = bond[i].cccd_num * sizeof(struct ble_cccd_s);
fwrite(bond[i].cccd, 1, sz, fp);
}
fclose(fp);
}
int onLoadBondInfo(int num, struct ble_bondinfo_s *bond)
{
int i;
FILE *fp;
int stored_num;
int sz;
size_t ret;
fp = fopen(BONDINFO_FILENAME, "rb");
if (fp == NULL)
{
return 0;
}
ret = fread(&stored_num, 1, sizeof(int), fp);
if (ret != sizeof(int))
{
printf("Error: could not load due to %s read error.\n",
BONDINFO_FILENAME);
fclose(fp);
return 0;
}
g_ble_bonded_device_num = (stored_num < num) ? stored_num : num;
sz = g_ble_bonded_device_num * sizeof(struct ble_cccd_s *);
g_cccd = (struct ble_cccd_s **)malloc(sz);
if (g_cccd == NULL)
{
printf("Error: could not load due to malloc error.\n");
g_ble_bonded_device_num = 0;
}
for (i = 0; i < g_ble_bonded_device_num; i++)
{
ret = fread(&bond[i], 1, sizeof(struct ble_bondinfo_s), fp);
if (ret != sizeof(struct ble_bondinfo_s))
{
printf("Error: could not load all data due to %s read error.\n",
BONDINFO_FILENAME);
printf("The number of loaded device is %d\n", i);
g_ble_bonded_device_num = i;
break;
}
if (bond[i].cccd_num > 1)
{
printf("Error: could not load all data due to invalid data.\n");
printf("cccd_num does not exceed the number of characteristics\n");
printf("that is set by this application.\n");
printf("The number of loaded device is %d\n", i);
g_ble_bonded_device_num = i;
break;
}
/* Because only cccd is pointer member, load it individually. */
sz = bond[i].cccd_num * sizeof(struct ble_cccd_s);
g_cccd[i] = (struct ble_cccd_s *)malloc(sz);
if (g_cccd[i] == NULL)
{
printf("Error: could not load all data due to malloc error.");
printf("The number of loaded device is %d\n", i);
g_ble_bonded_device_num = i;
break;
}
bond[i].cccd = g_cccd[i];
ret = fread(bond[i].cccd, 1, sz, fp);
if (ret != sz)
{
printf("Error: could not load all data due to %s read error.\n",
BONDINFO_FILENAME);
printf("The number of loaded device is %d\n", i);
g_ble_bonded_device_num = i;
break;
}
}
fclose(fp);
return g_ble_bonded_device_num;
}
void free_cccd(void)
{
int i;
if (g_cccd)
{
for (i = 0; i < g_ble_bonded_device_num; i++)
{
if (g_cccd[i])
{
free(g_cccd[i]);
}
}
free(g_cccd);
g_cccd = NULL;
}
}
void onMtuSize(uint16_t handle, uint16_t sz)
{
printf("negotiated MTU size(connection handle = %d) : %d\n", handle, sz);
}
void onEncryptionResult(uint16_t handle, bool result)
{
printf("Encryption result(connection handle = %d) : %s\n",
handle, (result) ? "Success" : "Fail");
}
void show_uuid(BLE_UUID *uuid)
{
int i;
printf("uuid : ");
switch (uuid->type)
{
case BLE_UUID_TYPE_UUID128:
/* UUID format YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY */
for (i = 0; i < BT_UUID128_LEN; i++)
{
printf("%02x", uuid->value.uuid128.uuid128[BT_UUID128_LEN - i - 1]);
if ((i == 3) || (i == 5) || (i == 7) || (i == 9))
{
printf("-");
}
}
printf("\n");
break;
case BLE_UUID_TYPE_BASEALIAS_BTSIG:
case BLE_UUID_TYPE_BASEALIAS_VENDOR:
/* UUID format XXXX */
printf("%04x\n", uuid->value.alias.uuidAlias);
break;
default:
printf("Irregular UUID type.\n");
break;
}
}
void onWrite(struct ble_gatt_char_s *ble_gatt_char)
{
int i;
/* If receive connected device name data, this function will call. */
printf("%s [BLE] start\n", __func__);
printf("handle : %d\n", ble_gatt_char->handle);
show_uuid(&ble_gatt_char->uuid);
printf("value_len : %d\n", ble_gatt_char->value.length);
printf("value : ");
for (i = 0; i < ble_gatt_char->value.length; i++)
{
printf("%02x ", ble_gatt_char->value.data[i]);
}
printf("\n");
printf("%s [BLE] end\n", __func__);
}
void onRead(struct ble_gatt_char_s *ble_gatt_char)
{
/* If receive connected device name data, this function will call. */
printf("%s [BLE] \n", __func__);
}
void onNotify(struct ble_gatt_char_s *ble_gatt_char, bool enable)
{
/* If receive connected device name data, this function will call. */
printf("%s [BLE] start \n", __func__);
printf("handle : %d\n", ble_gatt_char->handle);
show_uuid(&ble_gatt_char->uuid);
if (enable)
{
printf("notification enabled\n");
ble_is_notify_enabled = true;
}
else
{
printf("notification disabled\n");
ble_is_notify_enabled = false;
}
printf("%s [BLE] end \n", __func__);
}
/* Do not used now */
void ble_peripheral_exit(void)
{
int ret;
/* Turn OFF BT */
ret = bt_disable();
if (ret != BT_SUCCESS)
{
printf("%s [BT] BT disable failed. ret = %d\n", __func__, ret);
}
/* Finalize BT */
ret = bt_finalize();
if (ret != BT_SUCCESS)
{
printf("%s [BT] BT finalize failed. ret = %d\n", __func__, ret);
}
}
gps_main.ino
/*
* GPS Function
*
*/
/**
* @brief Turn on / off the LED0 for CPU active notification.
*/
void Led_isActive(void)
{
int state = 1;
if (state == 1)
{
ledOn(PIN_LED0);
state = 0;
}
else
{
ledOff(PIN_LED0);
state = 1;
}
}
/**
* @brief Turn on all LED:Setup start.
*/
void setup_start_led_driver(void)
{
ledOn(PIN_LED0);
ledOn(PIN_LED1);
ledOn(PIN_LED2);
ledOn(PIN_LED3);
}
/**
* @brief Turn off all LED:Setup done.
*/
void setup_done_led_driver(void)
{
ledOff(PIN_LED0);
ledOff(PIN_LED1);
ledOff(PIN_LED2);
ledOff(PIN_LED3);
}
/**
* @brief Setup Gnss
*/
void setup_gnss(int begin_message)
{
if (begin_message != 0)
{
Serial.println("Gnss begin error!!");
exit(0);
}
else
{
Gnss.select(GPS);
Gnss.select(GLONASS);
Gnss.select(QZ_L1CA);
}
}
void setup_gnss_cold_start(int cold_begin_message)
{
if (cold_begin_message != 0)
{
Serial.println("Gnss start error!!");
exit(0);
}
else
{
Serial.println("Gnss setup OK");
}
}
/**
* @brief Turn on / off the LED1 for positioning state notification.
*
* @param [in] state Positioning state
*/
void Led_isPosfix(bool state)
{
if (state)
{
ledOn(PIN_LED1);
}
else
{
ledOff(PIN_LED1);
}
}
/**
* @brief Turn on / off the LED3 for error notification.
*
* @param [in] state Error state
*/
void Led_isError(bool state)
{
if (state)
{
ledOn(PIN_LED3);
}
else
{
ledOff(PIN_LED3);
}
}
/**
* @brief %Print position information.
*/
void print_pos(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
/* print time */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
Serial.print(StringBuffer);
snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06ld, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
Serial.print(StringBuffer);
/* print satellites count */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
Serial.print(StringBuffer);
/* print position data */
if (pNavData->posFixMode == FixInvalid)
{
Serial.print("No-Fix, ");
}
else
{
Serial.print("Fix, ");
}
if (pNavData->posDataExist == 0)
{
Serial.print("No Position");
}
else
{
Serial.print("Lat=");
Serial.print(pNavData->latitude, 6);
Serial.print(", Lon=");
Serial.print(pNavData->longitude, 6);
}
Serial.println("");
}
/**
* @brief %Print satellite condition.
*/
void print_condition(SpNavData *pNavData)
{
char StringBuffer[STRING_BUFFER_SIZE];
unsigned long cnt;
/* Print satellite count. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites);
Serial.print(StringBuffer);
for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
{
const char *pType = "---";
SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
/* Get satellite type. */
/* Keep it to three letters. */
switch (sattype)
{
case GPS:
pType = "GPS";
break;
case GLONASS:
pType = "GLN";
break;
case QZ_L1CA:
pType = "QCA";
break;
case SBAS:
pType = "SBA";
break;
case QZ_L1S:
pType = "Q1S";
break;
case BEIDOU:
pType = "BDS";
break;
case GALILEO:
pType = "GAL";
break;
default:
pType = "UKN";
break;
}
/* Get print conditions. */
unsigned long Id = pNavData->getSatelliteId(cnt);
unsigned long Elv = pNavData->getSatelliteElevation(cnt);
unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
/* Print satellite condition. */
snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2ld] Type:%s, Id:%2ld, Elv:%2ld, Azm:%3ld, CN0:", cnt, pType, Id, Elv, Azm );
Serial.print(StringBuffer);
Serial.println(sigLevel, 6);
}
}
送信データ
float型で定義されている緯度、経度のデータをそのまま送信できたらいいのですが、今回使用したライブラリにあるble_characteristic_notifyという関数はuint8_t型のデータを扱うため、sprintf関数を使って文字列で送信バッファに格納しています。精度を保つためにも、小数点第6桁までを送信することを優先しました。
緯度、経度の小数点第6桁までの値をdata変数に格納する
sprintf(data, "%.6f,%.6f", lat, lon);
GPS衛星の指定
各国の管轄にあるGPS信号のいずれかを利用します。
受信できなかった場合はエラーとし、他の衛星との受信結果を得られるようにしています。
GPS・・・アメリカ
GLONASS・・・ロシア
QZ_L1CA・・・日本
受信衛星の指定
Gnss.select(GPS); Gnss.select(GLONASS); Gnss.select(QZ_L1CA);
Webアプリ
Web bluetooth APIを利用し、Web側をBLE Central、Spresense側をBLE Peripheralとした通信を行います。
Start notificationsのボタンクリックにより、SpresenseをBLEの通信を確立させます。
さらにGoogle map APIを利用してGoogle map上に現在位置と自動車の場所が分かるようにしました。
※個人の位置情報が出てしまうため墨入れしてます。ご了承ください。
※GPS非搭載のタブレットを使用したため、若干現在位置がずれてしまっていますが、
Spresenseの位置はほとんどズレが無いため十分に探索できる結果です。
反省点
- 送信バッファにはビットシフト演算のハンドリングがあればスマートにできたかもしれない。
- 動作モードを分けて停車時の位置情報を1度のみ送信するモードを設けておけば消費電力も下げられるかもしれない。
今後の課題、計画
- ボタン電池が切れると使えなくなるので自動車エンジンオン中に充電、エンジンオフで評価ボードの電源オンができる電源周りのハード構築
- 消費電力を抑えるための省電力化
- 要望があれば、LTEやWi-Fiでの通信も検討する
- 筐体づくり
最後に
全体を通して約2カ月ほど仕事終わりに開発に打ち込みましたが、アイデアを形にする楽しさを味わえました。
昔トランジスタラジオを発明したSONYの歴史を振り返りながら、ものづくりをする情熱のようなものを存分に味わえる機会を得ることもできました。ハード(電源周り)、ソフト(webアプリ)の両面で作ることができてとても勉強になりました。
ドキュメントが丁寧に整備されており、日本語で説明されていて理解がしやすいのも良いポイントだと思います。これからも様々なことにSPRESENSEとチャレンジし成長していけたらと考えています。また、本開発を通して、様々な人と交流できるきっかけになれたら幸いです。
-
yochan
さんが
2023/12/31
に
編集
をしました。
(メッセージ: 初版)
-
yochan
さんが
2023/12/31
に
編集
をしました。
-
yochan
さんが
2024/01/01
に
編集
をしました。
-
yochan
さんが
2024/01/08
に
編集
をしました。
-
yochan
さんが
2024/01/08
に
編集
をしました。
-
yochan
さんが
2024/01/13
に
編集
をしました。
-
yochan
さんが
2024/01/13
に
編集
をしました。
-
yochan
さんが
2024/01/13
に
編集
をしました。
ログインしてコメントを投稿する