こんにちは!この記事では、 株式会社Octa Roboticsが開発・提供している ロボット・設備間連携に特化したマルチベンダー型のインターフェースサービス「LCI」 について、ロボットからの利用方法を連載形式で紹介していきます。
前回の記事では、通信プロトコルの「エレベーター呼出階・行き先階指定(CallElevator)」を実装しました。
今回は、「エレベーターの状態取得(RequestElevatorStatus)」について実装を行っていきます。
エレベーターの状態取得(RequestElevatorStatus)に関しては、今回と次回の2回に分けて実装を行います。
おさらい
エレベーターの状態取得について、再確認していきましょう。
エレベーターの状態取得では、以下の手順でロボットとLCI&エレベーター間でMQTT通信を行います。
- ロボットからエレベーターにRequestElevatorStatusを送信
- エレベーターがRequestElevatorStatusを受信
- エレベーターからロボットにElevatorStatusを送信
- ロボットがElevatorStatusを受信
ElevatorStatusのresultが1の場合は成功、ElevatorStatusのresultが2、3、99の場合は失敗とみなします。
次は、トピック(メッセージの宛先)とペイロード(メッセージの中身)を確認していきましょう。
プロトコルの仕様
RequestElevatorStatusとElevatorStatusの仕様を確認していきます。
トピック(メッセージの宛先)
| プロトコル | トピック名 |
|---|---|
| RequestElevatorStatus | /lci/<bldg_id>/<bank_id>/<elevator_id>/RequestElevatorStatus/<robot_id> |
| ElevatorStatus | /lci/<bldg_id>/<bank_id>/<elevator_id>/ElevatorStatus/<robot_id> |
第3回で使用した設定ファイル:server_config_simulator_1-1.yamlを利用する場合には、以下になります。
| プロトコル | トピック |
|---|---|
| RequestElevatorStatus | /lci/simulator/1/1/RequestElevatorStatus/_uClosc2 |
| ElevatorStatus | /lci/simulator/1/1/ElevatorStatus/_uClosc2 |
- bldg_id : simulator(設定ファイル内のlci_bldg_id)
- bank_id : 1(設定ファイル内のlci_bank_id)
- elevator_id : 1(設定ファイル内のlci_elevator_id)
- robot_id : _uClosc2(開発用ロボットアカウントのID)
ペイロード(メッセージの中身)
| プロトコル | ペイロード |
|---|---|
| RequestElevatorStatus | { "timestamp":<timestamp>, "robot_id":<robot_id> } |
| ElevatorStatus | { "result":<result>, "floor":<floor>, "door":<door>, "direction":<direction>, "timestamp":<timestamp>, "requested_robot_id":<requested_robot_id>, "requested_timestamp":<requested_timestamp> } |
- timestamp : RequestElevatorStatusもしくはElevatorStatusを送信した時間(エポック秒)
- robot_id : RequestElevatorStatusを行うロボットのID(今回は_uClosc2)
- result : RequestElevatorStatusの結果(1:成功、2:失敗、3:その他エラー、99:管制運転中)
- floor : 現在のエレベーターがいるフロア
- door : ドアの開閉状態(エレベーター)
- direction : エレベーターの移動方向(LCIでは必ず3)
- requested_robot_id : RequestElevatorStatusを行なったロボットのID(今回は_uClosc2)
- requested_timestamp : RequestElevatorStatusが送られてきた時間
ElevatorStatusのdoorは、ドアの状態に応じて以下の値を返します。
| 値 | フロントドア状態 | リアドア状態 |
|---|---|---|
| 0 | not完全開 | not完全開 |
| 1 | 完全開 | not完全開 |
| 2 | not完全開 | 完全開 |
| 3 | 完全開 | 完全開 |
※ 同時開放は現行法で禁止されているため、3は使われない
directionについては、LCIではサポート外のため必ず3が入ります。
RFA規格においては、以下のように定義されています。
| 値 | 状態 |
|---|---|
| 0 | 停止中 |
| 1 | 下に移動 |
| 2 | 上に移動 |
補足:ペイロード内のfloorについて
ペイロード内のfloorは、フロアの名称を表す文字列であるfloor_idに従います。
floor_idは、設定ファイル内におけるlci_floor_listに記載があります。
今回使用している設定ファイル、server_config_simulator-1-1.yamlでは以下のように記載されています。
# floor name list from the bottom to the top
lci_floor_list:
- ['B1', True, False]
- 'E'
- 'G'
- 'L'
- '1F'
- '2F'
- '3F'
- ['4F', True, False]
- 'M5'
- 'M6'
- ['8F', True, True]
- ['R', False, True]
フロアの名称であるfloor_idは、以下の規則に従って命名されています。
-
建物図面上の略号を用いる場合
- 例えば、'A', 'B', 'G', 'LG', 'UG', 'L', 'M', 'P', 'R'などがあります
- 同じ略号で複数フロアがある場合は、区別をつけるため’A1’、’A2’のように数字を末尾につけます
-
建物図面上のフロアの名称が数字の場合
- 0,1,2,3といった数字だけでフロアが表記されている場合は、末尾に’F’をつけます
- 例)'0F', '1F', '2F', '3F'
サンプルコードの確認
サンプルコードのエレベーター状態取得に関連する箇所を確認していきましょう。
do_request_elevator_status
ここでは、以下のことを行なっています。
- ペイロードの作成
- トピックの作成
- メッセージのパブリッシュ
- ElevatorStatusのレスポンスを待つ
def do_request_elevator_status(self):
if not self.is_registered():
return ElevatorStatus()
# requested_time = int(time.time() * 1000)
requested_time = int(time.time() * 1000)/1000
payload = json.dumps({
'timestamp': requested_time,
'robot_id': self.robot_id})
api = 'RequestElevatorStatus'
topic = f'{self.topic_prefix}/{self.elevator_id}/{api}/{self.robot_id}'
self._publish(topic, payload)
return self.wait_response(api, requested_time, 3.0)
メイン処理
# Main routine
if __name__ == '__main__':
#---省略---#
#エレベーターへの状態取得
res = lci_client.do_request_elevator_status()
lci_client.logger.debug(res)
time.sleep(1)
サンプルコードの改良
RequestElevatorStatusでは、エレベーターの呼び出し成功(CallElevator)から降車完了(RobotStatus, state:2)まで2秒間隔で行う必要性があります。
加えて、ElevatorStatus内のresultが2, 3, 99の場合はエラー処理を実施する必要性があります。
サンプルコードではこれらの処理は未実装です。
そのため、これらの処理を行えるようにサンプルコードを改良する必要性があります。
RequestElevatorStatusを2秒間隔で行う理由は、
- エレベーターの到着をなるべく早く把握し、乗降をもたつかずに開始するため
- ドアが開いた後、素早く乗降を開始することで、人の割り込み、誤乗車の可能性を下げる(通常系)
-
resultに応じたエラー情報をなるべく早く把握し、ロボットのエラー処理を速やかに実行するため
- エレベーターのドアを通過している際にエラーが生じると連携が解除され、ドアが閉まる(異常系)
resultの意味と発生条件
はじめにElevatorStatus内のresultの意味と発生条件について確認しましょう。
| 評価順 | の値 | 意味 | 発生条件 |
|---|---|---|---|
| 1 | 3 | その他エラー | ペイロードのフィールドの一部又は全部が設定されていない |
| 2 | 3 | その他エラー | トピック名のrobot_idと、ペイロードrobot_idが一致しない |
| 3 | 99 | 管制運転中 | エレベーターが管制運転中のため連携不能 |
| 4 | 3 | その他エラー | エレベーターがロボット連携モードにも関わらず、ロボットが利用登録されていない(状態のミスマッチ) |
| 5 | 2 | 拒否(失敗) | ・エレベーターがロボット連携モードになっていない ・他のロボットが利用中 ・エレベーターがロボット連携モードに遷移中 ・エレベーターがロボット連携モードを解除中 |
| 6 | 3 | その他エラー | エレベーターが、設定ファイル外の階に居る |
| 7 | 1 | 成功 | エレベーターの現在の居る階、ドアの開閉状態を取得できた |
resultが2(拒否)、3(その他エラー)の場合、 floor, door 及び direction はペイロードに含まれません。
99の場合は、物件に応じて含まれる場合と含まれない場合があります。(LCI Boxを導入した施設では含まれ、LCI Bridgeを導入した施設では含まれません)
各resultの値に応じたロボットの動作
先ほどの表をもとに、resultの値に対してロボットがどのように動作するかを決めていきます。
今回は仕様書をもとに以下のように定めます。
| result | resultの意味 | ロボット側の動作 |
|---|---|---|
| 1 | 成功 | 次のステップに進む |
| 2 | 拒否(失敗) | 異常シーケンスに遷移 |
| 3 | その他エラー | 異常シーケンスに遷移 |
| 99 | 管制運転中 | 異常シーケンスに遷移 |
LCIからの応答が一定時間経過してもない場合は、異常シーケンスに遷移します。
フロー図
表をもとに、フロー図を作成しました。
手順としては、以下になります。
- stop_eventがsetされているか確認
- stop_event = threding.Event()
- setされている場合はループ終了
- setされていない場合はRequestElevatorStatusを送信
- RequestElevatorStatusを送信
- ElevatorStatusを受信したか確認
- 10秒間返信がない場合は、異常シーケンスに進む
- resultの値が1か確認
- 1でない場合は、異常シーケンスに進む
- ペイロード内のfloorとdoorの値を変数に代入
- 2秒間待機
ElevatorStatusの最大待機時間は10秒としました。
実装したコード
フロー図をもとに追記した変数や関数を記載します。
追記した変数
追記した変数とそれぞれの役割は以下です。
-
self.floor_value- エレベーターがいるフロアの情報を代入するための変数
-
self.door_value- エレベーターのドアにおける開閉情報を代入するための変数
-
self.stop_event- RequestElevatorStatusを終了させたい場合のフラグ
class LciClient:
def __init__(self):
self.logger = logging.getLogger('lci_client')
self.mqtt_client = None
self.robot_id = None
self.timestamp = None
self.elevator_id = None
self.registered = False
self.timeout_sec = None
self.floor_list = []
self.dry_run_registered = False
#---追記---#
self.floor_value = None
self.door_value = None
self.stop_event = threading.Event()
#---------#
メッセージを受信し、送信したメッセージのTopicにRequestElevatorStatusが含まれている場合、エレベーターのフロア情報をself.floor_valueに、エレベーターのドアに関する開閉情報をself.door_valueに代入します
def msg_callback(self, topic: str, payload_kv: dict):
parsed_topic = LciClient.ParsedTopic(topic)
if parsed_topic.api == 'message':
res = LciMessage()
res.orig_api = 'message'
res.type = payload_kv.get('type', 0)
res.content = payload_kv.get('content', 0)
res.robot_in_the_car = payload_kv.get('robot_in_the_car', 0)
res.timestamp = payload_kv.get('timestamp', 0)
self.message_queue.put(res)
return
elif parsed_topic.orig_api == '':
return
elif parsed_topic.orig_api == 'RequestElevatorStatus':
res = ElevatorStatus()
res.orig_api = 'RequestElevatorStatus'
res.floor = payload_kv.get('floor', 0)
res.door = payload_kv.get('door', 0)
res.direction = payload_kv.get('direction', 0)
#---追記---#
self.floor_value = res.floor
self.door_value = res.door
#---------#
start_request_elevator_status
後ほど説明するdo_request_elevator_status関数をスレッドとして動作させます。
def start_request_elevator_status(self):
thread_request_elevator_status = threading.Thread(target = self.do_request_elevator_status)
thread_request_elevator_status.start()
stop_request_elevator_status
後ほど説明するdo_request_elevator_status関数のループを終了させます。
def stop_request_elevator_status(self):
self.stop_event.set()
do_request_elevator_status
フロー図をもとに実装した関数です。
2秒間隔でRequestElevatorStatusを送り続けます。
self.stop_eventをsetすることでループを終了、ElevatorStatusが10秒経過しても受信できない場合およびres.result(ElevatorStatus)の値が1でない場合self.registeredをFalseにします。
self.registeredがFalseになると、これ以降のシーケンスが行われなくなります。
def do_request_elevator_status(self):
time_out = 10
while not self.stop_event.is_set():
res = self.request_elevator_status(time_out)
if res is not None:
if res.result != 1:
self.registered = False
self.logger.error(f"Request Elevator Status is failed code : {res.result}")
break
else:
self.logger.debug(res)
else:
self.registered = False
self.logger.error("RequestElevatorStatus is None")
break
time.sleep(2)
request_elevator_status
def request_elevator_status(self, time_out):
if not self.is_registered():
return ElevatorStatus()
# requested_time = int(time.time() * 1000)
requested_time = int(time.time() * 1000)/1000
payload = json.dumps({
'timestamp': requested_time,
'robot_id': self.robot_id})
api = 'RequestElevatorStatus'
topic = f'{self.topic_prefix}/{self.elevator_id}/{api}/{self.robot_id}'
self._publish(topic, payload)
return self.wait_response(api, requested_time, time_out)
メイン処理
出発階への呼び出し後、start_request_elevator_status関数にてスレッドを動作させます。
降車完了(do_robot_status(RobotStatus.HAS_GOT_OFF))を行う前に、stop_request_elevator_status()関数によりスレッドを停止させます。
if __name__ == '__main__':
#---省略---#
#出発階への呼び出し
res = lci_client.do_call_elevator('B1', '1F')
lci_client.logger.debug(res)
time.sleep(1)
#エレベーターへの状態取得
#追記
lci_client.start_request_elevator_status()
lci_client.logger.debug("Start Request Elevator Status")
time.sleep(1)
#乗り込み
res = lci_client.do_robot_status(RobotStatus.KEEP_DOOR_OPEN)
lci_client.logger.debug(res)
time.sleep(1)
#乗り込み完了
res = lci_client.do_robot_status(RobotStatus.HAS_ENTERED)
lci_client.logger.debug(res)
time.sleep(1)
#行き先階への登録
res = lci_client.do_call_elevator('B1', '1F')
lci_client.logger.debug(res)
time.sleep(1)
#降車
res = lci_client.do_robot_status(RobotStatus.KEEP_DOOR_OPEN)
lci_client.logger.debug(res)
time.sleep(1)
#エレベーター状態取得終了
lci_client.stop_request_elevator_status()
lci_client.logger.debug("End Request Elevator Status")
time.sleep(1)
#降車完了
res = lci_client.do_robot_status(RobotStatus.HAS_GOT_OFF)
lci_client.logger.debug(res)
time.sleep(1)
#利用解除
res = lci_client.do_release()
lci_client.logger.debug(res)
time.sleep(1)
動作確認
今回は、下記のように一部コードを変更して、ElevatorStatusのresult値を書き換えることで動作確認を行います。
def msg_callback(self, topic: str, payload_kv: dict):
parsed_topic = LciClient.ParsedTopic(topic)
if parsed_topic.api == 'message':
res = LciMessage()
res.orig_api = 'message'
res.type = payload_kv.get('type', 0)
res.content = payload_kv.get('content', 0)
res.robot_in_the_car = payload_kv.get('robot_in_the_car', 0)
res.timestamp = payload_kv.get('timestamp', 0)
self.message_queue.put(res)
return
elif parsed_topic.orig_api == '':
return
elif parsed_topic.orig_api == 'RequestElevatorStatus':
res = ElevatorStatus()
res.orig_api = 'RequestElevatorStatus'
res.floor = payload_kv.get('floor', 0)
res.door = payload_kv.get('door', 0)
res.direction = payload_kv.get('direction', 0)
self.floor_value = res.floor
self.door_value = res.door
else:
res = LciResponse()
res.orig_api = parsed_topic.orig_api
#ElevatorStatusのresultを変更する
#---追記---#
if parsed_topic.orig_api == 'RequestElevatorStatus':
#result: 1, 2, 3, 99のいずれかを指定
res.result = 1
else:
res.result = payload_kv.get('result', 0)
#---------#
次はコードを実行した際のログを確認していきましょう。
resultが1(成功)の場合
約2秒間おきにRequestElevatorStatusを送信、RequestElevatorStatusの送信ループの停止後にRobotStatusを送信しています。
ログを確認しやすいように、エレベーター状態取得(RequestElevatorStatus)と利用解除(Release)以外のシーケンスのログは削除しています。
2025-12-03 11:27:44,642 DEBUG Sending PUBLISH (d0, q1, r0, m6), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-12-03 11:27:44,762 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (156 bytes)
・・・
2025-12-03 11:27:46,813 DEBUG Sending PUBLISH (d0, q1, r0, m9), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-12-03 11:27:46,915 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (156 bytes)
・・・
2025-12-03 11:27:48,925 DEBUG Sending PUBLISH (d0, q1, r0, m11), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-12-03 11:27:49,071 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (157 bytes)
2025-12-03 11:27:50,098 DEBUG End Request Elevator Status
2025-12-03 11:27:51,101 DEBUG Sending PUBLISH (d0, q1, r0, m13), 'b'/lci/simulator/1/1/RobotStatus/_uClosc2'', ... (69 bytes)
2025-12-03 11:27:51,136 DEBUG Received PUBACK (Mid: 13)
2025-12-03 11:27:51,255 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/RobotStatusResult/_uClosc2', ... (119 bytes)
resultが2(拒否)の場合
RequestElevatorStatus以降のシーケンスを行わず、利用解除後に連携を終了しています。
2025-09-26 09:40:25,109 DEBUG Sending PUBLISH (d0, q1, r0, m6), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-09-26 09:40:25,109 DEBUG Start Request Elevator Status
2025-09-26 09:40:25,150 DEBUG Received PUBACK (Mid: 6)
2025-09-26 09:40:25,265 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (157 bytes)
2025-09-26 09:40:25,266 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:40:25,273 ERROR Request Elevator Status is failed code : 2
2025-09-26 09:40:26,114 DEBUG None
2025-09-26 09:40:27,120 DEBUG None
ERROR:root:CallElevator is failed!
2025-09-26 09:40:28,121 DEBUG None
2025-09-26 09:40:29,127 DEBUG None
2025-09-26 09:40:30,129 DEBUG End Request Elevator Status
2025-09-26 09:40:31,135 DEBUG Sending PUBLISH (d0, q1, r0, m7), 'b'/lci/simulator/1/1/Release/_uClosc2'', ... (53 bytes)
2025-09-26 09:40:31,171 DEBUG Received PUBACK (Mid: 7)
2025-09-26 09:40:31,277 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ReleaseResult/_uClosc2', ... (115 bytes)
2025-09-26 09:40:31,285 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:40:31,298 DEBUG orig_api: 'Release', result: '1', elevator_id: '1', timestamp: '1758847231.214', requested_robot_id: '_uClosc2', requested_timestamp: '1758847231.134'
resultが3(その他エラー)の場合
RequestElevatorStatus以降のシーケンスを行わず、利用解除後に連携を終了しています。
2025-09-26 09:47:13,328 DEBUG Sending PUBLISH (d0, q1, r0, m6), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-09-26 09:47:13,328 DEBUG Start Request Elevator Status
2025-09-26 09:47:13,364 DEBUG Received PUBACK (Mid: 6)
2025-09-26 09:47:13,435 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (157 bytes)
2025-09-26 09:47:13,436 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:47:13,436 ERROR Request Elevator Status is failed code : 3
2025-09-26 09:47:14,329 DEBUG None
2025-09-26 09:47:15,331 DEBUG None
ERROR:root:CallElevator is failed!
2025-09-26 09:47:16,335 DEBUG None
2025-09-26 09:47:17,340 DEBUG None
2025-09-26 09:47:18,344 DEBUG End Request Elevator Status
2025-09-26 09:47:19,346 DEBUG Sending PUBLISH (d0, q1, r0, m7), 'b'/lci/simulator/1/1/Release/_uClosc2'', ... (53 bytes)
2025-09-26 09:47:19,380 DEBUG Received PUBACK (Mid: 7)
2025-09-26 09:47:19,491 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ReleaseResult/_uClosc2', ... (115 bytes)
2025-09-26 09:47:19,491 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:47:19,512 DEBUG orig_api: 'Release', result: '1', elevator_id: '1', timestamp: '1758847639.411', requested_robot_id: '_uClosc2', requested_timestamp: '1758847639.346'
resutが99(その他エラー)の場合
RequestElevatorStatus以降のシーケンスを行わず、利用解除後に連携を終了しています。
2025-09-26 09:51:25,751 DEBUG Sending PUBLISH (d0, q1, r0, m6), 'b'/lci/simulator/1/1/RequestElevatorStatus/_uClosc2'', ... (53 bytes)
2025-09-26 09:51:25,752 DEBUG Start Request Elevator Status
2025-09-26 09:51:25,791 DEBUG Received PUBACK (Mid: 6)
2025-09-26 09:51:25,877 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ElevatorStatus/_uClosc2', ... (157 bytes)
2025-09-26 09:51:25,877 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:51:25,916 ERROR Request Elevator Status is failed code : 99
2025-09-26 09:51:26,757 DEBUG None
2025-09-26 09:51:27,762 DEBUG None
ERROR:root:CallElevator is failed!
2025-09-26 09:51:28,768 DEBUG None
2025-09-26 09:51:29,773 DEBUG None
2025-09-26 09:51:30,776 DEBUG End Request Elevator Status
2025-09-26 09:51:31,778 DEBUG Sending PUBLISH (d0, q1, r0, m7), 'b'/lci/simulator/1/1/Release/_uClosc2'', ... (53 bytes)
2025-09-26 09:51:31,815 DEBUG Received PUBACK (Mid: 7)
2025-09-26 09:51:31,987 DEBUG Received PUBLISH (d0, q1, r0, m1), '/lci/simulator/1/1/ReleaseResult/_uClosc2', ... (115 bytes)
2025-09-26 09:51:31,987 DEBUG Sending PUBACK (Mid: 1)
2025-09-26 09:51:32,005 DEBUG orig_api: 'Release', result: '1', elevator_id: '1', timestamp: '1758847891.943', requested_robot_id: '_uClosc2', requested_timestamp: '1758847891.777'
その他
- 本記事は、LCIプロトコル仕様書(オンライン)のv2025-10-04を参考に作成・加筆しています。
- LCI関連の開発に必要な情報が記載されている開発者用ポータルは以下からアクセスできます。
- 各種資料は以下から閲覧・ダウンロードできます。
- 開発用アカウントの発行は、以下からお問い合わせください。
連載記事リスト
- (1)はじめに・自己紹介・システム概要
- (2)開発用アカウント発行・サンプルコード
- (3)MQTTのブローカー接続・MQTTについて
- (4)エレベーター連携の全体シーケンス
- (5)エレベーター利用登録(Registration)
- (6)エレベーター呼出階・行き先階指定(CallElevator)
- (7)エレベーターの状態取得(RequestElevatorStatus)
- (8)エレベーターの状態取得2(RequestElevatorStatus)
他の記事もチェックしてみてください!
次回の記事では、引き続き通信プロトコルの「エレベーターの状態取得」についてサンプルコードを改良する予定です!
ご興味があれば「いいね」やフォローをいただけると励みになります!

