AWS RoboMaker入門 ~デモ起動からコード修正、実機デプロイまで~

AWS RoboMaker入門 ~デモ起動からコード修正、実機デプロイまで~:


はじめに

AWS RoboMakerは、2018年11月25日〜11月30日に行われた re:invent で発表された新サービスです。今回は、AWS RoboMakerのデモアプリを元に、クラウド上でのシミュレーション実行からデモプログラムの修正と確認、及び実際のロボットへのデプロイまで行ってみたいと思います。


AWS RoboMakerとROS

AWSのドキュメントによれば、AWS RoboMakerは「インテリジェントなロボットアプリケーションを容易に開発、シミュレート、デプロイできるサービス」とのことです。

AWS RoboMaker is a service that makes it easy to develop, simulate, and deploy intelligent robotics applications at scale.
ここでいう「ロボットアプリケーション」は、ROSで書かれたアプリケーションを指します。ROSは世界で広く使われているロボットアプリケーション開発用のミドルウェアで、ハードウェアの抽象化やデバイスドライバ、メッセージ通信処理等のライブラリなど、ロボットアプリケーションを開発する上で必要になる様々な機能を提供します。

ROS (Robot Operating System) provides libraries and tools to help software developers create robot applications. It provides hardware abstraction, device drivers, libraries, visualizers, message-passing, package management, and more.
ロボットを動作させるためには様々なセンサーやモーター等を協調して動作させる必要がありますが、それらの制御を毎回モノリシックに実装するのは無理があります。そこで、それぞれの部品を制御する再利用性の高い小さなプログラムが、相互に必要なデータをメッセージとしてやり取りすることで分散協調動作を行い、全体としてロボットを適切に動作させることが最善となります。ROSを用いることで、このような分散アプリケーションを容易に実装できるようになります。


Hello World デモを動かしてみよう

ということで、まずはAWS RoboMakerのサンプルアプリを動かしてみます。リージョンはバージニア北部にしました。(以下の手順や画像は、2018/12/11時点のものです。)


AWS RoboMakerのコンソールを開く

ブラウザからAWS RoboMakerのコンソールを開きます。12/11時点で、Management ConsoleからRoboMakerのコンソールを検索できるようになっています。



01.png



Hello World デモのシミュレーションコンテナを起動する

"Try sample application" から "Hello world" デモを選択し、画面下端の "Launch simulation job"をクリックします。



02.png

03.png

04.png


CloudFormationによって、Hello Worldデモ用のROSアプリケーションやシミュレーションジョブが準備されます。



05.png


CloudFormationが完了し、シミュレーションジョブが "Preparing" から "Running" になるのを待ちます。



06.png


この時点で、Hello worldデモのROSアプリケーションが準備され、RoboMakerに登録されています。その実体は、CloudFormationによって作成されたS3のバケットにアップロードされています。



07.png




08.png


また、Hello WorldデモのROSアプリケーションがどのように動作するのかをシミュレートするためのシミュレーションアプリケーションも準備されています。ROSアプリケーションと同様、実体はS3バケットにあります。



09.png


なおHello worldデモは、ROSで動作する教育用の自律移動ロボットであるTurtlebot3 Waffle Piをロボットのモデルとして採用しているようです。


Turtlebot3 Waffle Pi



シミュレーションでHello worldデモの動作を確認する

3クリックでシミュレーションコンテナが立ち上がったので、Hello worldデモでロボットがどのような動作をするのか確認してみます。

"Gazebo" をクリックし、コンテナ上で動作しているGazebo1に接続します。新たにブラウザのウィンドウが立ち上がり、ブラウザ上にGazeboのGUIが表示されます2



10.png


GazeboのGUI上をしばらく眺めていると、Turtlebot3 Waffle Piがゆっくりと自転していることがわかります。Hello worldデモのROSアプリケーションは、ロボットをZ軸の周りに一定速度で自転させるような動作が実装されているようですね。



robomaker_helloworld_1.gif


なおシミュレーション環境は、dockerコンテナとして動作している模様です。



11.png



Hello World デモのコードを修正する

では次に、このHello worldデモを改造してみましょう。ROSアプリケーションはPythonやC++で書くことが多いのですが、AWS RoboMakerはCloud9を利用したブラウザ上で動作するROS開発環境も提供しているため、新たに開発環境を構築する必要はありません。便利ですね!


VPCを作成する

RoboMakerのROS開発環境を入れておくためのVPCを作成しておきます。Public Subnetを一つ持つシンプルなVPCで十分です。


ROS開発環境を起動する

"Development environments" から "Create environment" をクリックします。


12.png


ROS開発環境名とインスタンスタイプを入力し、さきほど作成したVPCを指定して "Create" をクリックします。


13.png


CloudFormationによってEC2インスタンスが立ち上がり、Cloud9によるROS開発環境が起動します。"Open environment"をクリックすると、新たにブラウザのウィンドウが立ち上がります。


14.png


"AWS RoboMaker sample applications" から "Hello World" をクリックし、Hello worldデモのROSアプリケーションのうちロボットの動作を指示しているROSパッケージをROS開発環境に取り込みます3



15.png




16.png



ROSワークスペースを初期化する

ROSでは、ワークスペースと呼ばれるディレクトリの配下で各々のパッケージのソースコードを実装していきます。RoboMakerでは "robot_ws" と "simulation_ws" という二つのワークスペースが使われますので、それぞれ初期化し、ビルドが通るか確認します4



17.png


最下部の "bash" タブから、次のコマンドを実行します。エラーが発生せず、正常にビルドできたことを確認してください。

$ sudo apt update 
$ sudo apt install python-rosinstall -y 
$ rosdep update 
$ cd $HOME/environment/HelloWorld/ 
$ cd robot_ws 
$ rosws update 
$ rosdep install --from-paths src --ignore-src -r -y 
$ colcon build 
$ cd ../simulation_ws/ 
$ rosws update 
$ rosdep install --from-paths src --ignore-src -r -y 
$ colcon build 


Hello worldデモのソースコードを確認する

無事にビルドできたので、Hello worldデモのソースコードを読んでみます。Hello worldデモでロボットを操作しているROSパッケージは、Pythonで書かれています5。そのため、ROSに詳しくなくても、読むのはそれほど難しくありません。次のPythonスクリプトを開いてください。

$HOME/environment/HelloWorld/robot_ws/src/hello_world_robot/nodes/rotate



18.png


実はHello worldデモのROSパッケージは、このrotateというPythonスクリプトが全ての処理を担っています。ROS自体の解説はページが膨大になってしまうため割愛しますが、rotateがやってることは次の1点だけです。

  • 0.1秒に1回、/cmd_velというROS Topicへ、ロボットの並進速度と回転速度を定義した Twist という型のメッセージをpublishする
rotate
import rospy 
from geometry_msgs.msg import Twist 
 
class Rotator(): 
    def __init__(self): 
        self._cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1) 
 
    def rotate_forever(self): 
        self.twist = Twist() 
 
        r = rospy.Rate(10) 
        while not rospy.is_shutdown(): 
            self.twist.angular.z = 0.1 # <- rotate velocity (rad/s) 
            self._cmd_pub.publish(self.twist) 
            rospy.loginfo("Rotating robot: %s", self.twist) 
            r.sleep() 
 
 
def main(): 
    rospy.init_node('rotate') 
    try: 
        rotator = Rotator() 
        rotator.rotate_forever() 
    except rospy.ROSInterruptException: 
        pass 
 
if __name__ == '__main__': 
    main() 
Turtlebot3のモーターを制御するROSパッケージは、この /cmd_vel をsubscribeしており、Twistで示された並進速度と回転速度になるように、イイカンジに動輪のモーターを制御してくれます。

Hello worldデモでは、 self.twist.angular.z = 0.1毎秒0.1ラジアンでz軸周りに回転する ように指定しています。そのためシミュレーションで見たように、反時計回りでゆっくりとロボットが回転するのです。


Hello worldデモのソースコードを修正する

ということで、次はロボットの動作を修正してみましょう。回転だけでなく、前(x軸正)にも 0.05 m/sで進むことにします。これにより、ロボットは直径1mの円を描いて反時計回りにゆっくり動くことになります。

@@ -10,6 +10,7 @@ 
 
         r = rospy.Rate(10) 
         while not rospy.is_shutdown(): 
+            self.twist.linear.x = 0.05 # <- linear velocity (m/s) 
             self.twist.angular.z = 0.1 # <- rotate velocity (rad/s) 
             self._cmd_pub.publish(self.twist) 
             rospy.loginfo("Rotating robot: %s", self.twist) 
@@ -25,4 +26,4 @@ 
         pass 
修正した rotate を保存し(Ctrl-SやCmd-S等のショートカットキーが使えます)、メニューバーの "RoboMaker Run > Build > HelloWorld Robot" でROSパッケージをビルドします。



19.png


シミュレーション用アプリケーションは修正していませんが、ついでに "RoboMaker Run > Build > HelloWorld Simulation" でビルドしておきます。

次に、シミュレーション環境にデプロイできるようにバンドルします。メニューバーの "RoboMaker Run > Bundle > HelloWorld Robot" から、ROSアプリケーションをバンドルしてください(初回は色々とライブラリをダウンロードしてくるため、時間がかかります)。

同様に、 "RoboMaker Run > Bundle > HelloWorld Simulation" からシミュレーションアプリケーションもバンドルしておきます。


修正したHello worldデモをシミュレートする

では、修正したROSパッケージをシミュレーションコンテナにデプロイし、ロボットの動作を確認しましょう。

RoboMakerのシミュレーションコンテナは、デフォルトでは1時間で終了します。最初に起動したシミュレーションコンテナが終了している場合、その環境をCloneして新たにシミュレーションコンテナを起動してください。



20.png

21.png


シミュレーションコンテナが起動したら、ROS開発環境のメニューバーから "RoboMaker Simulation > Connect" でコンテナに接続します。



22.png

23.png


シミュレーションコンテナに接続したら、 "RoboMaker Simulation > Restart With New Bundles" で先ほどバンドルしたROSアプリケーションとシミュレーションアプリケーションをデプロイし、シミュレーションを再起動します(各バンドルのアップロードやコンテナの再起動を行うため、少し時間がかかります)。



24.png

25.png


シミュレーションコンテナのStatusが "Restarting" から "Running" になったら、準備完了です。Gazeboを開いてみましょう。



robomaker_helloworld_2.gif


ロボットが直径1mの円を描いて移動するようになりました。


実機へデプロイする

最後に、修正したROSアプリケーションをAWS Greengrassを用いてTurtlebot3の実機へデプロイします。

ただし私の手元にあるのがTurtlebot3 Waffle(ControllerにRaspberry PiではなくIntel Jouleを使ったモデル)のため、Turtlebot3 Waffle Piとは少し手順が異なります。


ロボットへROSアプリケーションをデプロイするための権限を設定する

まず最初に、インターネット越しにロボットへROSアプリケーションをデプロイできるようにするためのPolicyとRoleをIAMに設定します。


IAM Policyを作成する

以下のjsonから "RoboMaker_HelloWorld_Qiita_Policy" という名前のPolicyを登録します。
バケット名 awsrobomakerhelloworld-999999999999-bundlesbucket-xxxxxxxxxxxx は、CloudFormationが作成したS3のバケット名に置き換えてください。

RoboMaker_HelloWorld_Qiita_Policy
{ 
    "Version": "2012-10-17", 
    "Statement": [ 
        { 
            "Effect": "Allow", 
            "Action": [ 
                "robomaker:UpdateRobotDeployment" 
            ], 
            "Resource": "*" 
        }, 
        { 
            "Effect": "Allow", 
            "Action": [ 
                "s3:List*", 
                "s3:Get*" 
            ], 
            "Resource": ["arn:aws:s3:::awsrobomakerhelloworld-999999999999-bundlesbucket-xxxxxxxxxxxx/*"] 
        } 
    ] 
} 


IAM Roleを作成する

"RoboMaker_HelloWorld_Qiita_Role" という名前で、Greengrassを信頼するRoleを作成します。この際、先ほど作成した "RoboMaker_HelloWorld_Qiita_Policy" permission Policyを付与します。



26.png

27.png

28.png


作成された "RoboMaker_HelloWorld_Qiita_Role" を開き、 "Trust relationships" の "Edit trust relationship" をクリックします。



29.png


次のように、greengrassに加えてlambdaも信頼関係に追加します。

{ 
  "Version": "2012-10-17", 
  "Statement": [ 
    { 
      "Effect": "Allow", 
      "Principal": { 
        "Service": [ 
          "lambda.amazonaws.com", 
          "greengrass.amazonaws.com" 
        ] 
      }, 
      "Action": "sts:AssumeRole" 
    } 
  ] 
} 


30.png



RoboManagerにRobotを登録する

次に、"Fleet managment > Robots > Create Robot" から、Robotを作成します。



31.png


今回デプロイするTurtlebot3 WaffleはIntel Jouleを用いているため、アーキテクチャはX86_64を選択しています(Turtlebot3 Waffle Piならば、 ARMHFになるはず)。

またIAM Roleには、先ほど作成したRoleを指定してください。



32.png


Robotを作成すると、AWS Greengrassのcore softwareと、Greengrassに接続するための秘密鍵をダウンロードできるようになります。
注意: 秘密鍵は(おそらく)このページでしかダウンロードできないため、落とし忘れ無きように!!



33.png



greengrassのソフトウェアと秘密鍵をTurtlebot3 WaffleにSCPする

ダウンロードしたgreengrassのcoreソフトウェアと秘密鍵を、Turtlebot3 Waffleへscpします。

local:~$ scp ./Downloads/greengrass-linux-x86-64-1.7.0.tar.gz turtlebot3@turtlebot3.local:/home/turtlebot3 
local:~$ scp ./Downloads/Turtlebot3_Waffle-setup.zip turtlebot3@turtlebot3.local:/home/turtlebot3 


Turtlebot3 WaffleにAWS Greengrass coreをセットアップする

Turtlebot3 WaffleにSSHして、AWS Greengrassに接続できるようにセットアップします。


greengrass core用のuserとgroupを作成する

Greengrass coreは、ggc_userggc_groupを使うようになっているため、あらかじめ作成しておきます。

turtlebot3@turtlebot3:~$ sudo adduser --system ggc_user 
turtlebot3@turtlebot3:~$ sudo groupadd --system ggc_group 


ライブラリの存在を確認する

AWS Greengrass coreは、いくつかのライブラリが存在していることを前提としています。ロボットが要件を満たしているかを、ツールを使って確認します。

turtlebot3@turtlebot3:~$ cd /tmp 
turtlebot3@turtlebot3:/tmp$ git clone https://github.com/aws-samples/aws-greengrass-samples.git 
turtlebot3@turtlebot3:/tmp$ cd aws-greengrass-samples/greengrass-dependency-checker-GGCv1.7.0/ 
turtlebot3@turtlebot3:/tmp/aws-greengrass-samples/greengrass-dependency-checker-GGCv1.7.0$ sudo ./check_ggc_dependencies 
エラーが出てないことを確認します。

nodejs6.10java8が無いという警告が出ますが、これは問題ありません。)


AWS Greengrass coreと秘密鍵を展開する

scpしたAWS Greengrass coreのソフトウェアと秘密鍵を/opt/greengrassへ展開します。

turtlebot3@turtlebot3:~$ cd ~ 
turtlebot3@turtlebot3:~$ sudo tar -xzvf greengrass-linux-x86-64-1.7.0.tar.gz -C /opt/ 
turtlebot3@turtlebot3:~$ sudo unzip -o Turtlebot3_Waffle-setup.zip -d /opt/greengrass 
またロボットがMQTT over TLSでAWS IoT Coreに接続できるように、Root CAもダウンロードしておいてください。

turtlebot3@turtlebot3:~$ cd /opt/greengrass/certs/ 
turtlebot3@turtlebot3:/opt/greengrass/certs$ sudo wget -O root.ca.pem http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem 
turtlebot3@turtlebot3:/opt/greengrass/certs$ wc /opt/greengrass/certs/root.ca.pem 
  27   30 1758 /opt/greengrass/certs/root.ca.pem 


AWS Greengrass coreを起動する

greengrassd startコマンドで、AWS Greengrass coreのデーモンを起動してください。セットアップが上手く行っていれば、バックグラウンドでgreengrassのデーモンプロセスが起動しているはずです。

turtlebot3@turtlebot3:/opt/greengrass/certs$ cd /opt/greengrass/ggc/core/ 
turtlebot3@turtlebot3:/opt/greengrass/ggc/core$ sudo ./greengrassd start 
Setting up greengrass daemon 
Validating hardlink/softlink protection 
Waiting for up to 40s for Daemon to start 
 
Greengrass successfully started with PID: 15381 
turtlebot3@turtlebot3:/opt/greengrass/ggc/core$ ps aux | grep greengrass 
root     15381  0.6  0.4 384320 16824 pts/8    Sl   14:51   0:00 /opt/greengrass/ggc/packages/1.7.0/bin/daemon -core-dir /opt/greengrass/ggc/packages/1.7.0 -greengrassdPid 15376 
turtleb+ 15407  0.0  0.0  15236  1024 pts/8    S+   14:51   0:00 grep --color=auto greengrass 


RoboManagerにFleetを登録する

Fleetは、Robotをグループ化するものです。FleetにRobotを登録することで、それらのロボットにROSアプリケーションをデプロイできるようになります。 "Fleets > Create fleet" をクリックします。


34.png


"Turtlebot3_Waffle_fleet" という名前でFleetを作成します。


35.png


作成されたFleetに、先ほど登録したRobotを追加します。まず "Register new" をクリックします。


36.png


登録したRobotを選択し、 "Register robot" をクリックします。


37.png


FleetにRobotが追加されていることを確認します。


38.png



(必要であれば)ROSアプリケーションをクロスコンパイルする

Turtlebot3 WaffleはX86_64アーキテクチャなので不要ですが、Turtlebot3 Waffle PiなどCPUアーキテクチャが異なるロボットにアプリケーションをデプロイする場合は、CPUアーキテクチャに合わせてROSアプリケーションをクロスコンパイルしてバンドルし、S3バケットにアップロードする必要があります。

詳細は、RoboMakerのドキュメンテーション Step 5: Deploy Robot Application To bundle and deploy the Hello World robot applicationの 1. ~ 4. を参照してください。


Versionを作成する

RoboMakerは、ROSアプリケーションのバージョンを指定して実機へデプロイします。シミュレーションしか行っていない現時点ではバージョンが一つも作成されていないため、まずバージョンを作成します。

"RobotApplication" からROSアプリケーションを選択します。



39.png


"Create new version" をクリックし、新しいバージョンを作成します。



40.png

41.png


今回は初回リリースなので、"1"というバージョンが作成されました。



42.png


もしX86_64以外のアーキテクチャのROSアプリケーションをデプロイしたい場合は、ROSアプリケーションを選択した後 "Actions > Update" をクリック、S3にアップロードしたバンドルファイルをsource fileとして指定してください。


43.png


Deploymentを作成する

"Deployments > create deployment" から、Deploymentを作成します。

Turtlebot3 Waffle用に作成したFleetと、先ほど作成したバージョン "1" のRobot Applicationを指定します。

また、Package nameとして "hello_world_robot"を、Launch fileとして "deploy_rotate.launch" を入力し、 "Create" をクリックします。



44.png


指定したLaunch fileの実体は、 $HOME/environment/HelloWorld/robot_ws/src/hello_world_robot/launch 以下のdeploy_rotate.launch です。

deploy_rotate.launch
<launch> 
  <!-- bringup turtlebot3 --> 
  <include file="$(find turtlebot3_bringup)/launch/turtlebot3_robot.launch"/> 
 
  <!-- deploy rotate system --> 
  <include file="$(find hello_world_robot)/launch/rotate.launch"> 
    <arg name="use_sim_time" value="false"/> 
  </include> 
</launch> 
この deploy_rotate.lauch が呼び出されると、Turtlebot3の実機を動作させるためのROSパッケージ "turtlebot3_bringup" の turtlebot3_robot.launch と、今回改造した "hello_world_robot" パッケージの rotate.launch が起動します。

deploy.launch
<launch> 
  <!--  
       Using simulation time means nodes initialized after this 
       will not use the system clock for its ROS clock and  
       instead wait for simulation ticks.  
 
       See http://wiki.ros.org/Clock 
 
       Note: set to false for deploying to a real robot. 
  --> 
  <arg name="use_sim_time" default="true"/> 
  <param name="use_sim_time" value="$(arg use_sim_time)"/> 
 
  <!-- Rotate the robot on launch --> 
  <node pkg="hello_world_robot" type="rotate" name="rotate" output="screen"/> 
</launch> 
deploy.launch は、先ほど修正した rotate スクリプトを実行します。これらが起動することで、指定したようにTurtlebot3が動き出すようになります。


ROSアプリケーションをインターネット越しにリモートデプロイする

Deploymentが適切に作成されれば、ROSアプリケーションはTurtlebot3 Waffleの実機へ自動的にデプロイされ、指定した deploy_rotate.launch が自動起動してTurtlebot3 Waffleが動き出します。



45.png


turtlebot3_waffle.gif

もし上手く動かなかった場合は、 /opt/greengrass/ggc/var/log/user/<<region name>>/<<id>>/ 以下に作成されるログを確認してください。ROSアプリケーション起動失敗時のエラーが記録されているはずです。


注意点

  1. ドキュメントの間違い

    • 2018/12/11時点でのRoboMakerの公式ドキュメントの Step 5: Deploy Robot Application Bundle and deploy Hello World robot application では、Launch fileとして "rotate.launch" を指定するように記述されています。しかし"rotate.launch"を指定すると、ROSアプリケーションは正しくデプロイされますが、ロボットは動きません。これはTurtlebot3 Waffleのモーターなどを実際に動かすROSパッケージが起動されていないためです。
  2. ストレージ容量

    • RoboMakerのROSアプリケーションバンドルには、ROSの実行ライブラリからTurtlebot3用のROSパッケージまで、環境一式がまるごと入っています。S3からダウンロードしたバンドルファイル自身やそれを展開したディレクトリの容量も計算すると、今回のHello worldデモで、ざっくり 4.3GB の容量を費やしています。ストレージの空き容量には十分注意してください。
  3. ネットワーク

    • RoboMakerは、ROS Masterの接続先としてホスト名を用います。そのため、ホスト名で名前解決できる($ ping $(hostname) が返ってくる)ことを確認してください。


まとめ

ということで、AWS RoboMakerを用いてデモを改造したROSアプリケーションを実際のロボットにデプロイすることができました。

ブラウザだけあればROSアプリケーションを書いてシミュレーションできること、またインターネット越しにロボットへROSアプリケーションをデプロイできるのは、面白い仕組みだと思います。

ただし、AWS RoboMakerで構築したROSアプリケーションは、ROSアプリケーション全体をまるっとデプロイする形になっているため、ロボットにすでにデプロイされているROSパッケージと連携する場合や、外部ですでに起動しているROS Masterに接続する場合など、実際のロボット開発で遭遇しそうなシチュエーションでは少し戸惑うことになる気がします。

(ROSパッケージもcatkinではなくcolconでビルドしているため、通常のcatkinで作成されたROSワークスペースにそのままコピーすることもできませんし。)

このあたりは、今後もノウハウを蓄積する必要がありそうです。



  1. Gazeboとは、オープンソースの3Dロボットシミュレータです。物理エンジンを持ち、ロボットが実際の環境でどのように動作するかをシミュレーションすることができます。 



  2. ブラウザ上でコンテナ上のGazeboのGUIを表示する際には、AWSが買収したNICE Desktop Cloud Visualizationが使われているようです。 



  3. ROSのアプリケーションは、パッケージを基本として構成されます。ROSパッケージとは、ロボットのとある機能を簡単に再利用できるようにひとまとめにしたものです。Turtlebot3の動作を制御する機能はすでにROSパッケージとして公開されていますので、Hello worldデモではそのROSパッケージを再利用する形となっています。 



  4. RoboMakerで使われているROS(Kinetic)では、通常ビルドコマンドとしては catkin が用いられます。RoboMakerで用いている colcon は、ROS2(Bouncy)から採用されたビルドツールです。catkinにはROSパッケージ群をtarファイルとして一つにバンドルするような機能は無いため、あえてROS Kineticでは使われないcolconを採用したのでしょうか?ROS2やってない人にはツライ・・・ 



  5. ROS(Kinetic)が提供するPythonライブラリは、OS(Ubuntu 16.04)のPython2.7を参照しています。あえて苦労したくない人は、Python2系で実装するのが無難です。 


コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)