六腹町会

作って、計算して、読んだものの記録です

nRF51822のセントラル機能試験結果報告(後半)

(作成中:暫定公開:最終版は来週に公開予定です)

本記事の内容について、間違いや不明点があればご指摘願います。
疑問点があればいつでもお問い合わせください。(掲示板やメールはたまにしか確認していないので、ツイッターなら確実に連絡がつきます。)
また、本記事の内容について一切の権利を放棄しますので、自由に改変、拡散していただいても構いません。

【サンプルプログラムの修正】

今回はサンプルプログラムを修正してmbed HRM1017をセントラルとして使用します。
サンプルプログラム内にある通信関数やログ関数APPL_LOGは、開発ボード以外ではハードエラーの要因になるので削除しました。
また、mbed用にクロックの設定を外部水晶からRC発振に変更します。

①UUID作成

まずはble_app_multilink_centralのclient_handling.cやble_app_multilink_peripheralのmain.cのUUIDを変更します。

サンプルのUUID

#define MULTILINK_PERIPHERAL_BASE_UUID     {0xB3, 0x58, 0x55, 0x40, 0x50, 0x60, 0x11, \
                                           0xe3, 0x8f, 0x96, 0x08, 0x00, 0x00, 0x00,  \
                                           0x9a, 0x66}                                /**< 128bit UUID base used for example. */
#define MULTILINK_PERIPHERAL_SERVICE_UUID  0x9001                                     /**< Serrvice UUID over the 128-bit base used for the example. */
#define MULTILINK_PERIPHERAL_CHAR_UUID     0x900A                                     /**< Characteristic UUID over the 128-bit base used for the example. */

変更例

#define TEST_UUID_BASE {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x9A, 0xBC}
#define TEST_UUID_SERVICE 			0xFFFF
#define TEST_UUID_NOTIFY_CHAR 		0xAAAA

また、TEST_UUID_NOTIFY_CHAR がサンプルプログラムのMULTILINK_PERIPHERAL_CHAR_UUIDに相当します。

UUIDはネットのサイトやNordicのnRFgo studioで作成できるので詳細はここでは説明しません。

また、サンプルプロジェクトble_app_multilink_centralのUUIDを書き換えます。
例)
関数client_handling_init内

ble_uuid128_t base_uuid = MULTILINK_PERIPHERAL_BASE_UUID;
ble_uuid128_t base_uuid = TEST_UUID_BASE;

uuid.uuid = MULTILINK_PERIPHERAL_SERVICE_UUID;
uuid.uuid = TEST_UUID_SERVICE;

例)
関数db_discovery_evt_handler内

if ((p_characteristic->characteristic.uuid.uuid == MULTILINK_PERIPHERAL_CHAR_UUID)
if ((p_characteristic->characteristic.uuid.uuid == TEST_UUID_NOTIFY_CHAR)

他のUUIDも同様に置換します。
また、ble_app_multilink_peripheralも同様にUUIDを検索して置換ください。

②デバイス名作成

ble_app_multilink_centralのmain.cやble_app_multilink_peripheralのmain.cのDEVICE_NAMEを変更します。
サンプルのDEVICE_NAME

#define TARGET_DEV_NAME                  "Multilink"                                    /**< Target device name that application is looking for. */

ble_app_multilink_peripheralについては、ペリフェラルは異なるDEVICE_NAMEを作成して別々に書き込みます。この異なるペリフェラルのデバイス名をセントラルに記憶させることで、両者を識別できるようにします。

#define DEVICE_NAME                     "TEST_A"

#define DEVICE_NAME                     "TEST_B"

ble_app_multilink_centralについては、2つのDEVICE_NAMEを両方とも用意します。

#define TARGET_DEV_NAME_A                  " TEST_A "                                    /**< Target device name that application is looking for. */
#define TARGET_DEV_NAME_B                  " TEST_B"                                    /**< Target device name that application is looking for. */
③アドバタイジング検知時の処理

アドバタイジング検知時に呼び出されるmain.cの関数on_ble_evtの分岐BLE_GAP_EVT_ADV_REPORT内の処理を変更します。

type_data.p_dataにアドバタイジングパケットのデバイス名が格納されているので、それをmemcmp関数で比較して一致しているかを確認して分岐します。

デバイス名が一致していた場合、フラグ変数type_indexの一致していたペリフェラルを示すbitをアサートさせます。

switch (p_ble_evt->header.evt_id)
{
   case BLE_GAP_EVT_ADV_REPORT:
   {
      data_t adv_data;
      data_t type_data;

      // Initialize advertisement report for parsing.
      adv_data.p_data = p_ble_evt->evt.gap_evt.params.adv_report.data;
      adv_data.data_len = p_ble_evt->evt.gap_evt.params.adv_report.dlen;

      err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME, &adv_data, &type_data);
      if (err_code != NRF_SUCCESS)
      {
                // Compare short local name in case complete name does not match.
                err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME, &adv_data, &type_data);
      }

      // Verify if short or complete name matches target.
      //TARGET DEVICEがペリフェラルAの場合
      if ((err_code == NRF_SUCCESS) && (0 == memcmp(TARGET_DEV_NAME_A,type_data.p_data,type_data.data_len)))
      {
            err_code = sd_ble_gap_scan_stop();
            err_code = sd_ble_gap_connect(&p_ble_evt->evt.gap_evt.params.adv_report.peer_addr, &m_scan_param, &m_connection_param);

            //TARGET DEVICEがペリフェラルAと接続したことを示すフラグをアサート
            type_index |= TARGET_A;
      }
      //TARGET DEVICEがペリフェラルBの場合
      else if((err_code == NRF_SUCCESS) && (0 == memcmp(TARGET_DEV_NAME_B,type_data.p_data,type_data.data_len)))
      {							
            err_code = sd_ble_gap_scan_stop();
            err_code = sd_ble_gap_connect(&p_ble_evt->evt.gap_evt.params.adv_report.peer_addr, &m_scan_param, &m_connection_param);
								
            //TARGET DEVICEがペリフェラルBと接続したことを示すフラグをアサート
            type_index |= TARGET_B;
      }
      break;
}

ここでは以下の定数と変数を追加しています。

#define		TARGET_A		0x01
#define		TARGET_B		0x02

static uint8_t type_index;
④BLE接続後の処理

BLE接続時に呼び出されるmain.cのdevice_manager_event_handlerの分岐DM_EVT_CONNECTION内の処理を変更します。
アドバタイジング検知時にアサートしたtype_indexの値を判定して、p_handle->connection_idの値を配列ch_typeに格納します。
この処理が完了したらtype_indexは用済みなので、ペリフェラルを示すbitをクリアします。

   switch(p_event->event_id)
    {
        case DM_EVT_CONNECTION:
        #ifdef ENABLE_DEBUG_LOG_SUPPORT
            ble_gap_addr_t * p_peer_addr;
            p_peer_addr = &p_event->event_param.p_gap_param->params.connected.peer_addr;
        #endif // ENABLE_DEBUG_LOG_SUPPORT
            
            err_code = client_handling_create(p_handle, p_event->event_param.p_gap_param->conn_handle);
            APP_ERROR_CHECK(err_code);
									
            m_peer_count++;
				
            //TARGET DEVICE Aと接続したindex番号をバッファに格納
            if(TARGET_A == (TARGET_A & type_index))
            {
                 ch_type[0] = (p_handle->connection_id);
                 type_index ^= TARGET_A;		//フラグクリア										
            }
            //TARGET DEVICE Bと接続したindex番号をバッファに格納
            else if(TARGET_B == (TARGET_B & type_index))
            {
                 ch_type[1] = (p_handle->connection_id);
                 type_index ^= TARGET_B;		//フラグクリア
            }
				
            break;

ここで配列ch_typeをグローバル変数として追加しました。

uint8_t ch_type[2];
extern uint8_t ch_type[2];
⑤Characteristicの確認

BLE接続確立時に呼び出されるclient_handling.cの関数db_discovery_evt_handlerも修正します。
修正と言ってもNotifyのUUIDを置換するだけです。

if ((p_characteristic->characteristic.uuid.uuid == LOWFREQ_UUID_NOTIFY_CHAR)
⑥Notify

ペリフェラルからNotifyがあると呼び出されるon_evt_hvxを修正します。
この関数の変数indexはペリフェラルの番号を示しており、配列ch_typeに格納された値を比較することでペリフェラルAとBのどちらからのNotifyかが区別できます。
Notifyのデータはp_ble_evt->evt.gattc_evt.params.hvx.dataに格納されているので、私のプログラムではそれを一時退避バッファnotify_char_aやnotify_char_bに格納させました。
なお私はNotifyを1パケット20byteにしています。

static void on_evt_hvx(ble_evt_t * p_ble_evt, client_t * p_client, uint32_t index)
{
 uint8_t notify_char_a[20];
 uint8_t notify_char_b[20];
 uint8_t i;

 if (p_ble_evt->evt.gattc_evt.params.hvx.handle ==  p_client->srv_db.services[0].charateristics[p_client->char_index].characteristic.handle_value)
 {
     //ペリフェラルAの場合
     if(index == ch_type[0])
     {
          //Notifyデータの保存
          for(i=0; i<20; i++) {
              notify_char_a[i] =  p_ble_evt->evt.gattc_evt.params.hvx.data[i]; }
     }
     //ペリフェラルBの場合
     else if(index == ch_type[1])
     {
          //Notifyデータの保存
          for(i=0; i<20; i++) {
              notify_char_b[i] =  p_ble_evt->evt.gattc_evt.params.hvx.data[i]; }
     }

⑦Write

サンプルプログラムはNotifyしかできなくて不便だったので、以下を参照してWrite用関数を作成しました。
nrf51-ble-app-lbs communication with S120 Multilink - Nordic Developer Zone

void send(uint32_t type, uint8_t *data, uint8_t length)
{
	ble_gattc_write_params_t gattc_params;
	
	gattc_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
	gattc_params.handle = m_client[type].srv_db.services[0].charateristics[0].characteristic.handle_value;		//service handle
	gattc_params.len = length;
	gattc_params.offset = 0;
	gattc_params.write_op = BLE_GATT_OP_WRITE_CMD;     
	gattc_params.p_value = &data[0];

	sd_ble_gattc_write(m_client[type].srv_db.conn_handle, &gattc_params);

}

この関数の第1引数に送信したい対象ペリフェラルのch_typeを代入してください。
例えば

send(ch_type[0], &temp_data[0], 3);

で、3byteのデータがペリフェラルAに送信されます。

nRF51822のセントラル機能試験結果報告(前半)

本記事の内容について、間違いや不明点があればご指摘願います。
疑問点があればいつでもお問い合わせください。(掲示板やメールはたまにしか確認していないので、ツイッターなら確実に連絡がつきます。)
また、本記事の内容について一切の権利を放棄しますので、自由に改変、拡散していただいても構いません。

【何をしたいか】

1つのBLEモジュールnRF51822をセントラルとして、もう2つのnRF51822をペリフェラルとして使用します。
サンプルプログラムにはこれを実行するためのble_app_multilink_centralとble_app_multilink_peripheralというプロジェクトがあります。(ネットで名前を検索すれば、サンプルプログラムが見つかるはずです。)
前者がセントラル用で、後者がペリフェラル用です。

ただし、このセントラルは2つのペリフェラルをBLE接続に成功した順番に番号付けして区別します。
これは2つのペリフェラルがBLE接続のタイミングにより毎回異なる番号を持つことになるので、少し不便なことです。

f:id:rokuharatown:20160123191453j:plain

例えば、2体のロボットにBLEをペリフェラルとして搭載して、リモコンに搭載したセントラルBLEで操作するとします。
リモコンのスイッチAでロボットAを動かし、スイッチBでロボットBを動かします。
ですがセントラルnRF51822 が接続した順番に番号付けすると、どちらの番号がロボットAとBのnRF51822なのか識別できません。
接続した順番でペリフェラルの識別番号が変わってしまうので、起動するごとに番号が変わります。するとスイッチAでロボットBが動いたりしてしまうわけです。

そこで次の方法でペリフェラルを区別させてみました。
ます2つのペリフェラルnRF51822にそれぞれ異なるデバイス名をつけます。デバイス名はアドバタイジングパケットに含まれるデータの1つです。
セントラルnRF51822はデバイス名と番号を対応付けることで、2つのペリフェラルを常時区別できるようになります。

f:id:rokuharatown:20160123191520j:plain

【環境】

今回の開発環境は以下の通りです。全体的に古い環境を使用しています。
SDK Ver6.1
ペリフェラルのソトデバイスS110 V7.1
セントラルのソフトデバイスS120 V1.0

以下では、ソフトデバイスの書き込みやペリフェラルの設定はできるものとみなして、セントラルの設定方法を中心に解説を行います。

サンプルプロジェクトはnRF51822開発ボードで動かすことを前提に解説し、修正したプロジェクトはmbed HRM1017で動かすことを前提に解説します。

【サンプルプロジェクトの分析】

まずは、app_multilink_centralが何をしているか分析してみます。
https://github.com/linklayer/BLEKey/tree/master/nordic/nrf51822/Board/nrf6310/s120/ble_app_multilink_central


セントラル機能のサンプルプロジェクトにはもう1つble_app_hrsがあります。ここでは詳しく説明しませんが(私もまだ十分理解できていないのです。)そちらも並行して参照すると理解がより深まると思います。

①UUIDの登録

関数client_handling_initにおいてBLE接続の対象とするペリフェラルのUUIDを設定しています。
セントラルはこのUUIDと一致しないペリフェラルとはBLE接続しません。

ble_uuid128_t base_uuid = MULTILINK_PERIPHERAL_BASE_UUID;	
uuid.uuid = MULTILINK_PERIPHERAL_SERVICE_UUID;	
②スキャン開始

BLE接続は、セントラルがペリフェラルの発信するアドバタイジングパケットをスキャンすることで確立します。
ですからセントラルのプログラムは、どこかでスキャン開始を指示しないといけません。
スキャン開始関数scan_startを実行することでセントラルは、ペリフェラルの送信するアドバタイジングパケットのスキャンを開始します。

サンプルプログラムでは、main関数の起動後に初期設定をした直後、scan_startを実行しています。

int main(void)
{	
    // Initialization of various modules.
    app_trace_init();
    leds_init();
    buttons_init();
    ble_stack_init();
    client_handling_init();
    device_manager_init();

    // Start scanning for devices.
    scan_start();

私が作成したプログラムでは、main関数でスキャン開始するのではなく、スイッチを押した時にスリープモードから復帰してスキャンを開始するという動作にしました。

関数scan_startの中身は、Flashへのアクセスができるかを確認した後に、スキャン開始許可しています。
もう1つのサンプルble_app_hrsではホワイトリストの初期化もしていましたが、今回は使用しないので省略します。
つまりサンプルble_app_multilink_centralの関数scan_startをそのまま使います。

③アドバタイジングパケットの検知

main.cの関数on_ble_evtには以下の2つの分岐が確認できます。
BLE_GAP_EVT_ADV_REPORT
BLE_GAP_EVT_TIMEOUT

また、もう1つのサンプルble_app_hrs_cにはパラメータ更新の分岐もあるので必要な場合は追加するといいと思います。
BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST

今回はBLE_GAP_EVT_ADV_REPORTに注目します。
これはペリフェラルが送信するアドバタイジングパケットを検知した時に発生するイベントです。
このイベントにより、構造体変数adv_dataにアドバタイジングパケットが格納されます。
アドバタイジングパケットの構造については、BLEの参考書や他の人が書いているブログなどをご参照ください。

この関数において具体的に何をしているかを以下に列挙します。

(1)
アドバタイジングパケットのデータ格納

adv_data.p_data = p_ble_evt->evt.gap_evt.params.adv_report.data;

(2)
アドバタイジングパケットのデータ長格納

adv_data.data_len = p_ble_evt->evt.gap_evt.params.adv_report.dlen;

(3)
アドバタイジングパケットのデータadv_dataにtype:BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAMEのデータが有るか無いかを検索
→有る場合はBLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAMEのデータをtype_dataに格納

err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,	&adv_data, &type_data);

→無い場合はアドバタイジングパケットのデータadv_dataにtype:BLE_GAP_AD_TYPE_SHORT_LOCAL_NAMEのデータが有るか無いかを検索
→有る場合はBLE_GAP_AD_TYPE_SHORT_LOCAL_NAMEのデータをtype_dataに格納

if (err_code != NRF_SUCCESS)				
{ // Compare short local name in case complete name does not match.				
                err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME,  &adv_data, &type_data);	
}			

(4)
なお、adv_report_parseでは以下を行っている。

アドバタイジングパケットのデータ部を抜き出して取得する。

p_data = p_advdata->p_data;

index(データの何バイト目かを示す変数)がアドバタイジングパケットのデータ長を上回るまで検索する

while (index < p_advdata->data_len)

アドバタイジングパケットのデータ部は複数に区切られており、各部の最初の1byte目が1区切りのデータ長を、2 byte目が1区切りのデータtypeを示しているのでそれを取得。

uint8_t field_length = p_data[index]; 
uint8_t field_type   = p_data[index+1];	

アドバタイジングパケットに目当てのtypeと一致するtypeがある場合、p_typedataにデータを格納し、p_typedataにデータ長を格納する。

p_typedata->p_data   = &p_data[index+2];					            
p_typedata->data_len = field_length-1;		

一致するtypeがない場合、次の区切りまでindexを移動する。

index += field_length+1;


(5)
アドバタイジングパケットから取得したデータtype_dataがターゲットデバイス名と一致しているかを比較

if ((err_code == NRF_SUCCESS) &&   (0 == memcmp(TARGET_DEV_NAME,type_data.p_data,type_data.data_len)))	

→一致した場合、スキャンを終了後、peer address、スキャンパラメータ、接続パラメータを指定してBLE接続を確立させる。
peer addressの説明は以下をご覧ください。
http://developer.nordicsemi.com/nRF51_SDK/nRF51_SDK_v7.x.x/doc/7.0.1/s120/html/a00069.html

err_code = sd_ble_gap_scan_stop();	

err_code = sd_ble_gap_connect(&p_ble_evt->evt.gap_evt.params.adv_report. peer_addr, &m_scan_param, &m_connection_param);

もう1つのサンプルble_app_hrs_cはもっと複雑な分岐をして、UUIDの確認などを行っていますが、基本的にしていることは同じです。
このイベントでは、検出したアドバタイジングパケットから必要なデータを抽出し、接続を確立しています。
複数ペリフェラルと接続してそれらを識別する場合は、ここで一工夫が必要になるのですが、それは後述いたします。

④BLE接続・BLE切断

BLE接続やBLE切断時に呼び出されるイベントがあります。
main.cの関数device_manager_event_handlerです。

BLE接続時にはDM_EVT_CONNECTIONへ分岐し、BLE切断時にはDM_EVT_DISCONNECTIONへ分岐します。

BLE接続時には以下のことをしています。
新規クライアント作成関数を実行し、

err_code = client_handling_create(p_handle, p_event->event_param.p_gap_param->conn_handle);

接続ペリフェラルカウントを加算して、設定した最大ペリフェラル接続数を超えていなければ、③で停止させていたスキャンを再開します。

m_peer_count++;
if (m_peer_count < MAX_PEER_COUNT)
{
   scan_start();
}


このとき、p_handle->connection_idにBLE接続したペリフェラルの番号が格納されます。


BLE切断時には以下のことをしています。

p_handleを破棄し、

err_code = client_handling_destroy(p_handle);

既に接続カウントが最大ペリフェラル接続数に達しているならば、停止しているスキャンを再開させて、接続ペリフェラルカウントを減算しています。

if (m_peer_count == MAX_PEER_COUNT)	
{	
scan_start();	
}	
m_peer_count--;	
⑤Characteristicの確認

BLE接続確立時にはclient_handling.cの関数db_discovery_evt_handlerも呼び出されます。

この関数では、アドバタイジングパケットから取得したcharacteristic数であるchar_countの上限まで網羅的に検索を行います。

for (i = 0; i < p_evt->params.discovered_db.char_count; i++)

アドバタイジングパケットから取得したcharacteristicの中から、こちらで設定したNotifyサービスのCHARACTER UUIDと一致するものを探します。
ここではMULTILINK_PERIPHERAL_CHAR_UUIDがそれです。
自作したペリフェラルの場合は、この設定を書き換えます。

if ((p_characteristic->characteristic.uuid.uuid == MULTILINK_PERIPHERAL_CHAR_UUID) && (p_characteristic->characteristic.uuid.type == m_base_uuid_type))

対象のcharacteristicが発見された場合、そのchracteristic番号を変数p_clientに保存してから、

p_client->char_index = i;

Notifyを有効にしています。

notif_enable(p_client);
⑥Notify

BLE接続確立後、ペリフェラルからNotifyがあると、client_handling.cの関数client_handling_ble_evt_handlerが呼び出されます。

この関数では、まずNotifyを送信したペリフェラルの情報を取得します。ここで④で取得したp_handle->connection_idと同じ番号が得られます。
このindex番号で、複数接続しているペリフェラルを区別しています。

uint32_t index = client_find(p_ble_evt->evt.gattc_evt.conn_handle);

その後、BLE_GATTC_EVT_HVXに分岐してclient_handling.cの関数on_evt_hvxを実行します。

case BLE_GATTC_EVT_HVX:	
 on_evt_hvx(p_ble_evt, p_client, index);	
 break;	

on_evt_hvxでは以下のことが行われています。

クライアント状態の確認

if ((p_client != NULL) && (p_client->state == STATE_RUNNING))

→問題がなければNotifyの判別
受信したハンドル p_ble_evt->evt.gattc_evt.params.hvx.handleが登録したハンドルと一致しており、かつデータ長さが1byteかどうかを確認します。

if((p_ble_evt->evt.gattc_evt.params.hvx.handle == p_client->srv_db.services[0].charateristics[p_client->char_index].characteristic.handle_value) && (p_ble_evt->evt.gattc_evt.params.hvx.len == 1))

ここではNotifyが1byteであることを前提にしていますが、私の作成したプログラムでは1パケット20byteにしているので、この条件は不要もしくは値を変更します。

→Notifyの判別OKの場合
BLE接続番号indexに対応した開発ボードのLEDを制御します。
Notifyデータが0なら点灯し、それ以外なら消灯します。
1番目にBLE接続したペリフェラルからのNotifyならばLED0が点灯や消灯し、
2番目にBLE接続したペリフェラルからのNotifyならばLED1が点灯や消灯します。

if (p_ble_evt->evt.gattc_evt.params.hvx.data[0] == 0)
{
    nrf_gpio_pin_clear(index + LED_PIN_NO_OFFSET);
}
else
{
    nrf_gpio_pin_set(index + LED_PIN_NO_OFFSET);
}


以上がサンプルプログラムの内容です。
セントラルとペリフェラルをBLE接続して、ペリフェラル側のスイッチを押すとNotifyが送信され、セントラル側のLEDのどれかが点いたり、消えたりするという動作をするわけです。

長くなって申し訳ありませんが、いよいよ次はこのサンプルプログラムを改造します。

C89頒布 電気回路表紙の修正方法

本記事は、コミックマーケットC89 31日木曜日 西地区 み-06aにおいて頒布した「電気回路になる表紙」の修正方法について説明いたします。

f:id:rokuharatown:20160110200620j:plain


この表紙はコミケで販売した同人誌を購入してくださった方に無料でサービスしたものです。
AgICの販売している銀ナノ粒子インクを用いて印刷することで、紙の上に電気回路を形成しています。
ボタン電池を電源として、チップLEDと7セグLEDを光らせる仕組みになっています。
この表紙の作成方法は本ブログのこちらの記事をご覧ください。

電気回路表紙の作り方 - 六腹町会


この表紙はまだ試作中のため品質が安定しておらず、売り物にならないと判断して、コミケでは購入者への無料サービス扱いにしました。
ですが考えてみますと、購入者の多くの方はこの表紙が欲しくてお金を払っていたに違いありません。
表紙が面白そうだからこそ購入したのに、その肝心の表紙が動かないということでは大変残念な思いをされたことでしょう。
それは大変申し訳ないことです。
そこで購入した皆様に対して可能な限りサポート、交換、修正を行い、正常に動作する品質の表紙を楽しんでもらいたいと考えました。



まず手始めに、全ての表紙が共通して抱えている「電源不安定」問題の修正方法について、ご家庭でもできる修正方法を本記事で解説させていただきます。

この表紙はボタン電池ホルダの接触が弱く、安定して電源が供給されません。
表紙を水平に置いているときはいいのですが、本を持ち上げたり、立てたりすると以下の写真のように電池と表紙の間に隙間ができて電気が不通になってしまいます。
f:id:rokuharatown:20160110200948j:plain:w400

両端の電極を接着剤で固定することで、この問題は解決します。
以下のように電池ホルダを抑えながら、電極の上から接着剤を塗り、乾くまで固定してください。
そうすることで紙と電極が固定されて、安定した通電が可能になります。
乾く前に手を離すと、電極と紙の隙間に接着剤が侵入して電気が通らなくなってしまうのでご注意ください。
f:id:rokuharatown:20160110201218j:plain


これを両端について行います。以下のように電池ホルダが表紙に固定されることで電源が安定して供給されるようになります。
f:id:rokuharatown:20160110202011j:plain


ですが、まれにこれでも接触が不十分な場合もあります。
そのような時は、導電テープを貼るという方法もありますが、その方法はまた別の機会に紹介したく思います。

他にもチップLEDと7セグLEDの接触不良で動作しない場合もあり、それらの修正は電子工作に慣れている人でないと難しいと思われます。
今後、電池ホルダの固定をしても動作しない表紙については、私の方で表紙を回収して、修正もしくは交換していきたいと考えています。

この記事を読まれた方の中に、コミケで本表紙を購入し、正常に動作していないという方がおられましたらご連絡ください。



以下余談


私は今回、コミケ初参加でした。
初めてのコミケでサークル参加というのは無謀だったと思いますが、知人のアドバイスや、コミケ当日にお会いした周囲の参加サークル様の助けで何とか無事に終えることができました。
この場を借りて、それらの方々にはお礼申し上げます。


初めて参加してみて、コミケというのはお祭りだと実感しました。
私の地元では全国から3日間で150万人も集まる規模の祭りがあるのですが、コミケはそれとよく似ていました。

祭りには、有象無象の人々が大量に集まります。
祭りの熱気を楽しみたい見物人、噂を聞いてやって来た外国人、神輿を担ぐ参加者、儀式を行う神職、一儲けしようと集まる商売人、ゴロ行為を働く裏家業者やヤクザ者、裏方に徹して祭りの世話をする町内会の人々、祭りを監督する行政機関や警察。
そこには、聖も俗も、良きも悪しきも入り混じることで生まれる活力と熱気があります。
コミケにもそれらの全てがありました。
簡単に言えば、コミケという場に参加して とても楽しかったです。


祭りは珍奇にして希少なるものを神へ奉納する場でもあります。
コミケでは同人誌がその奉納する物にあたると解釈できます。
私はせっかく祭りに参加するのだから、なるべく面白い物を奉納して参加者を楽しませたいと考えました。
そこで私は今回のような電気回路表紙を作成することを計画しました。

実際には、私事で恐縮ですが年末に仕事が忙しくなり、作業をできたのは29日と30日だけでした。
そのため動作検証に使える時間がなく、品質が不安定になり、参加者を十分に楽しませることができなかったと悔やんでいます。

次の機会があれば、十分な時間をかけて品質の安定した、更に珍奇な物を作成したいと思います。

電気回路表紙の作り方

「紙に電気回路を印刷する」
AgICの販売する銀ナノ粒子インクを用いることで、そんなことが実現できます。

私はコミケC89で販売した同人誌の表紙に電気回路を印刷しました。
f:id:rokuharatown:20160110224149j:plain:w400

この記事では、その制作方法を紹介したく思います。

①回路を描く

まずイラストレーターで回路を描きます。

f:id:rokuharatown:20160110214538j:plain:w400

イラストの大部分は単なる装飾で、実際に回路の役割を果たしている部分だけを抜き出すと以下のようになります。

f:id:rokuharatown:20160110214626j:plain:w400

②印刷準備

AgICで専用インクを購入します。
f:id:rokuharatown:20160110215210j:plain:w300 f:id:rokuharatown:20160110215302j:plain:w300


プリンタはLC12カートリッジに対応している以下の機種から適当な物を用意します。

MFC-J6710/J5910/J6510/J960/J955/J860
J825/J810/J710/J705
DCP-J940/J925/J840/J740/J725
J540/J525 シリーズ

私はAmazonで5,000円くらいの中古プリンタを購入しました。

カートリッジをプリンタにセットします。

f:id:rokuharatown:20160110215719j:plain:w400

セット後はプリンタの機能にある印刷品質チェックを実行して、以下のように全てのカートリッジから正常にインクが出ているのを確認します。
おそらく何度かノズルのクリーニングを行わないと、正常な状態にはならないと思います。

f:id:rokuharatown:20160110215734j:plain:w400

詳細な方法はYouTubeの解説動画をご覧ください。

www.youtube.com

www.youtube.com

➂印刷

AgICの販売する専用紙もしくは代替の光沢紙を購入します。

富士フィルム WPA455VA
富士フィルム WPA420HIC
コクヨ KJ-D12A4-20
ブラザー BP71GA4

印刷設定を最高画質、光沢紙に選択します。

f:id:rokuharatown:20160110220533p:plain:w400


あとは普通に印刷するだけです。
f:id:rokuharatown:20160110220626j:plain:w400

④表紙作成

印刷した紙を加工して本を包み込む表紙に仕立てます。

まず印刷した紙を筋押しします。
カッターの背面で溝を作り、折り曲げます。
f:id:rokuharatown:20160110221252j:plain:w370 f:id:rokuharatown:20160110221314j:plain:w370


厚紙に印刷した裏表紙を用意します。
f:id:rokuharatown:20160110221602j:plain:w400


この2つを貼合わせて表紙にします。
f:id:rokuharatown:20160110221724j:plain:w450

⑤部品の用意

表紙に貼り付ける部品は、チップLED、7セグLED、マイコンボタン電池ホルダの4つです。


マイコンには秋月電子で購入したR5F10Y16ASP使用 RL78マイコンモジュールを使用しています。

これにプログラムを書込みます。RENESASのE1を用いて、マイコンと自作治具を接続して書込みました。

f:id:rokuharatown:20160110221947j:plain:w450 f:id:rokuharatown:20160110222156j:plain:w200


なお裏表紙に印刷してあるプログラムが、このマイコンに書き込んだプログラムです。


RL78にピンを取り付けて、黒い固定部を取り外し、適当な長さに切り揃えます。

f:id:rokuharatown:20160110222358j:plain:w200 f:id:rokuharatown:20160110222410j:plain:w300


7セグLEDは入手できる中で、最も薄い物を選びました。
この7セグLEDはそのままでは通電性が悪いので、ハンダでピンを取り付けて端子に電気が通りやすくします。

f:id:rokuharatown:20160110222325j:plain:w300 f:id:rokuharatown:20160110222334j:plain:w300

⑥部品の貼り付け

本来ならば、この表紙に部品を取り付けるには、導電接着剤か導電テープを使用することが推奨されています。
ですが、導電接着剤は高価で量が少なく、導電テープは細かい部品の取り付けに不向きです。
同人誌は50部作成する予定だったので、表紙も50個用意する必要がありました。そのため部品を直接に紙と密着させて通電させる方法を採用しました。
ですが、この方法では品質が安定しないという問題があり、今後の課題となっています。


電源を供給して光り方を確認しながら部品を貼り付けます。
そのために安定化電源を接続して3Vを供給しながら作業を行います。
f:id:rokuharatown:20160110222611j:plain:w400 f:id:rokuharatown:20160110222616j:plain:w200


チップLEDを接着剤で取り付けます。
接着個所は前後の2箇所です。接着剤が乾くまで押さえつけます。
乾く前に手を放すと、チップLEDと表紙の間に接着剤が入り込んで電気が通らなくなってしまうのでご注意ください。

f:id:rokuharatown:20160110222630j:plain:w350 f:id:rokuharatown:20160110222636j:plain:w370

チップLEDを貼り付けると以下のようになります。
f:id:rokuharatown:20160110224536j:plain:w400


次に7セグLEDの裏にセメダインを塗って表紙に貼ります。
f:id:rokuharatown:20160110224418j:plain

この状態では7セグLEDが表紙に密着していないので、ピンを押さえつけながらハンダを溶かすと、ピンが下に滑り落ちて紙と密着し通電するようになります。
f:id:rokuharatown:20160110224428j:plain:w370 f:id:rokuharatown:20160110224436j:plain:w370

念のため接着剤でピンを固定します。
f:id:rokuharatown:20160110224508j:plain

7セグLEDを貼り付けると以下のようになります。
f:id:rokuharatown:20160110224517j:plain:w400


作業の中で一番難しいのがマイコンの貼り付けです。
重しでマイコンを固定して、指でピンを押しながら紙とピンがうまく密着していない端子を探します。
(指で押した時にLEDが光り、指を離した時に消えてしまう端子が、密着していない端子です。)

7セグLEDと同様に、ピンをハンダで溶かして紙と密着させます。
f:id:rokuharatown:20160110224551j:plain f:id:rokuharatown:20160110224603j:plain

ピンと紙が密着した状態でマイコンを押さえつけながら、接着剤でピンを固定します。
f:id:rokuharatown:20160110224636j:plain

マイコンを貼り付けると以下のようになります。
f:id:rokuharatown:20160110224649j:plain:w300


部品の貼り付けに成功すると、以下のようにLEDの点灯が確認できます。
f:id:rokuharatown:20160110224715j:plain:w400


最後にボタン電池ホルダをセメダインで取り付けます。
f:id:rokuharatown:20160110224739j:plain f:id:rokuharatown:20160110224754j:plain:w400


ボタン電池ホルダの電極を接着剤で固定して紙と密着させます。
実際に頒布した表紙は、この作業をしていなかったため、ボタン電池ホルダがうまく通電しないという不具合がありました。
f:id:rokuharatown:20160110224809j:plain f:id:rokuharatown:20160110224820j:plain


以上で電気回路表紙は完成です。
f:id:rokuharatown:20160110224846j:plain:w300