Ketunorobio が 2022年12月14日20時41分46秒 に編集
初版
タイトルの変更
RaspberryPi ZERO2Wで多関節2足歩行ロボット
タグの変更
RaspberryPi
ロボット
ブラウザ操作
joystick
カメラ
メイン画像の変更
記事種類の変更
製作品
本文の変更
過去にいくつか2足歩行ロボットを作ってきたのですが、見た目にあまりこだわってこなかったので、自分なりに見た目がイケてるやつを作ってみようかとなりました。 しかし見た目だけ変えるのは少し物足りないので、間接も増やして頭、肘、腰、なども動かせる「多関節2足歩行ロボット」にする事にしました。(これで多関節なのかはわかんないけど。。) となるとサーボモーターも多く使う事になるので、そこそこの大きさになりました。 ロボットは先日完成(仮)しましたので、今回はこの「多関節2足歩行ロボット」について、概要や作成過程等をまとめようと思います。 これからロボットを作る方の参考になれば幸いです。 ## 多関節2足歩行ロボット の概要 ### 外観 @[twitter](https://twitter.com/ketunorobio/status/1568206707830177795?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1568206707830177795%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) とりあえず手書きで外観をスケッチしてみました。 これを元に、サーボモーターやマイコン等の大きさを加味したサイズにしていきます。 ### ハードウェアの構成 外観のサイズが大方わかりましたので、内部に入れるマイコン等を決めます。 今回はカメラを付けて、ブラウザやbluetooth,bleで無線操作したいと思ったのと、ゆくゆくはROSなんかも入れてみたいなと思ったのでRaspberryPi ZERO2Wを使う事にしました。 構成は下記の通りです。 RaspberryPi ZERO2W ⇒ i2c ⇒ PCA9685 ⇒ サーボ11個 カメラはラズパイカメラを使いました。 バッテリーはLipoで2000mAh,放電Cレート2の物を使いました。瞬間最大で4Aまで出せるのでこれ1個でマイコンとサーボドライバの電源をまかないます。 ### 制御について 1,WEBサーバーにhtmlで操作画面を作りブラウザから操作可能にする。(カメラ画像あり) 2,bleでアナログコントローラーから操作可能にする。(カメラ画像なし) 各部位ごとの操作も可能にする。 なお、1,2,共に電源投入後に自動でプログラムが立ち上がるようにする。 ### 動作 前進、後退(腰の捻りを追加) 左右旋回 目の発光(LED)PWM制御も入れる ポーズ(中山きんに君のパワー) ブラウザ時はカメラ映像あり アナログコントローラー時は各部位を単体で動かせる 物理ボタンで電源ON,OFF 電源ON時、目を発光、その後ポーズ(パワー) WEBサーバー、およびアナログコントローラーの接続プログラムは電源ON後に自動で起動 ### プログラム ブラウザはHTML,css,js,pythonCGI アナログコントローラーはpython ## 外観の作成 ### CADスケッチ fusion360でボディのスケッチを作成。 @[twitter](https://twitter.com/ketunorobio/status/1568848966741295104?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1568848966741295104%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) ![キャプションを入力できます](https://camo.elchika.com/19476ab99db377f28f4e3a12a3156c7e545de029/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f63376431353531362d303832382d343163662d623133392d373531663964383239656234/) ![キャプションを入力できます](https://camo.elchika.com/ec5033616f3e89218d0847d7c0222b446c87814e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f31313138326236312d663632342d343634652d613834312d323038373030373064613865/) ![キャプションを入力できます](https://camo.elchika.com/32a8fbf11c05c82404baded738e4ff8babb6785d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f35313333623362652d643264322d343962642d393537342d376230616466643666666138/) ![キャプションを入力できます](https://camo.elchika.com/c7a9d095bd493a5b31449d3408972a69bc91268a/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f63393139656463332d363238302d346331642d626635642d626135363438616133363038/) ### 3Dプリント、部品格納 3Dプリンターで印刷、内部に部品を格納。 @[twitter](https://twitter.com/ketunorobio/status/1569604582103470081?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1569604582103470081%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) @[twitter](https://twitter.com/ketunorobio/status/1570341509026959361?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1570341509026959361%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) @[twitter](https://twitter.com/ketunorobio/status/1570715551542181888?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1570715551542181888%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) @[twitter](https://twitter.com/ketunorobio/status/1572196048642387968?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1572196048642387968%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) @[twitter](https://twitter.com/ketunorobio/status/1572556737420591109?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1572556737420591109%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) @[twitter](https://twitter.com/ketunorobio/status/1575072213186752512?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1575072213186752512%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) ## 配線と歩行テスト ### 配線 @[twitter](https://twitter.com/ketunorobio/status/1576863725809651712?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1576863725809651712%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) ### 歩行テスト @[twitter](https://twitter.com/ketunorobio/status/1576915438969098240?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1576915438969098240%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) なんとか動いてくれました。 全体の姿はこんな感じになりました。↓ ![キャプションを入力できます](https://camo.elchika.com/46449c7d8d956372fc0a0d75cc1214694c505704/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f63303765356132382d626533632d343937652d623262392d386237303962353535326565/) ![キャプションを入力できます](https://camo.elchika.com/77852d3d3b7ce82e2a857d6e29676746899c730b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f32613833656438362d363333392d343634312d613230622d643730633538303530653135/) ![キャプションを入力できます](https://camo.elchika.com/2a06420324b1143d502350ab5cfc178ab388e864/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f35383561613361342d656237392d343065362d393637302d386636303264353737653266/) ## プログラム ### ブラウザ(html/css,js,python) ※WEBサーバーはApacheを使用しています。カメラはmjpgstreamerを使用しています。またCGIを使う場合は各種設定変更が必要です。その辺の説明は長くなりますのでここでは割愛します。 ``` <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>テスト</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="style.css"> </head> <body> <div class="cam"> <img src="http://ローカルIP:8080/?action=stream"> </div> <main> <ul> <div class="tp"> <div class="b"> <li id="topl" class="ledoff">left</li> </div> <div class="a"> <li id="tops" class="ledoff">center</li> </div> <div class="c"> <li id="topr" class="ledoff">right</li> </div> </div> <div class="bc"> <div class="b"> <li id="leftforward" class="ledoff">1</li> </div> <div class="a"> <li id="forward" class="ledoff">↑</li> </div> <div class="c"> <li id="rightforward" class="ledoff">2</li> </div> </div> <div class="bc"> <div class="b"> <li id="left" class="ledoff">←</li> </div> <div class="a"> <div class="z"> <div class="y"> <li id="l" class="ledoff">ON</li> </div> <div class="x"> <li id="r" class="ledoff">OFF</li> </div> </div> </div> <div class="c"> <li id="right" class="ledoff">→</li> </div> </div> <div class="bc"> <div class="b"> <li id="leftbackward" class="ledoff">3</li> </div> <div class="a"> <li id="backward" class="ledoff">↓</li> </div> <div class="c"> <li id="rightbackward" class="ledoff">4</li> </div> </div> </ul> </main> <script src="jquery-3.6.1.min.js"></script> <script src="main.js"></script> </body> </html> ``` ``` * { margin: 0px; padding: 0px; } body { max-width: 600px; font-size: 18px; width: 100%; -webkit-touch-callout: none; -webkit-user-select: none; } img { width: 100%; } main { height: 50vh; background: skyblue; } ul { display: block; height: 40vh; list-style: none; padding-top: 10px; } .tp { display: flex; } .bc { display: flex; } .z { display: flex; } .a ,.bc, .d .y, .x, .tp { height: 12vh; } li { width: 90px; height: 70% ; margin-left: 5px; background: yellow; line-height: 60px; } #l, #r { width: 45px; margin-left: 5px; } .b { margin-left: auto; } .c { margin-right: auto; } ul li { text-align: center; } .a li, .b li, .c li, .d li { border: solid 1px; } .ledon { background: #f88888; } .n li { background: skyblue; } a:active { color: #ff2020; } ``` ``` $(function(){ let motor = "STOP"; function change_motor2() { motor = 'STOP'; } // 関数:モーターを動かすマクロ呼び出し function change_motor(typee) { motor = typee; if(typee == "FOWARD") { // 前進 //w().callMacro('FW'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'hhhh' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "BACKWARD") { //w().callMacro('BK'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'iiii' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "RIGHT") { //w().callMacro('RT'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'jjjj' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "LEFT") { //w().callMacro('LT'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'kkkk' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "STOP") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'ssss' } }); } else if(typee == "topl") { //w().callMacro('LT'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'topl' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "tops") { //w().callMacro('LT'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'tops' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "topr") { //w().callMacro('LT'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'topr' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "LEFTFORWARD") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'qqqq' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "RIGHTFORWARD") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'mmmm' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "L") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'gggg' } }); } else if(typee == "R") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'dddd' } }); } else if(typee == "LEFTBACKWARD") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'oooo' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } else if(typee == "RIGHTBACKWARD") { //w().callMacro('ST'); console.log(typee); $.ajax({ url: 'cgi-bin/recieve.py', type: 'post', data: {name: 'zzzz' } }).done(function(data){ change_motor2(); console.log(data); }).fail(function(){ console.log('failed'); }); } } // 「前進」ボタンが押されたときのイベント処理 $('#forward').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('FOWARD'); ff1 = setInterval(function(){ change_motor('FOWARD'); }, 2700); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); clearInterval(ff1); }); // 「後退」ボタンが押されたときのイベント処理 $('#backward').bind('touchstart', function() { if(motor == "STOP") { $(this).addClass('ledon'); change_motor('BACKWARD'); ff1 = setInterval(function(){ change_motor('BACKWARD'); }, 2700); } }).bind('touchend', function() { $(this).removeClass('ledon'); //change_motor('STOP'); clearInterval(ff1); }); // 「右」ボタンが押されたときのイベント処理 $('#right').bind('touchstart', function() { if(motor == "STOP") { $(this).addClass('ledon'); change_motor('RIGHT'); ff1 = setInterval(function(){ change_motor('RIGHT'); }, 1300); } }).bind('touchend', function() { $(this).removeClass('ledon'); //change_motor('STOP'); clearInterval(ff1); }); // 「左」ボタンが押されたときのイベント処理 $('#left').bind('touchstart', function() { if(motor == "STOP") { $(this).addClass('ledon'); change_motor('LEFT'); ff1 = setInterval(function(){ change_motor('LEFT'); }, 1300); } }).bind('touchend', function() { $(this).removeClass('ledon'); //change_motor('STOP'); clearInterval(ff1); }); $('#leftforward').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('LEFTFORWARD'); //ff1 = setInterval(function(){ //change_motor('LEFTFORWARD'); //}, 4500); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#rightforward').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('RIGHTFORWARD'); //ff1 = setInterval(function(){ //change_motor('RIGHTFORWARD'); //}, 3000); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#leftbackward').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('LEFTBACKWARD'); //ff1 = setInterval(function(){ //change_motor('LEFTBACKWARD'); //}, 5500); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#rightbackward').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('RIGHTBACKWARD'); //ff1 = setInterval(function(){ //change_motor('RIGHTBACKWARD'); //}, 3000); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#topl').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('topl'); //ff1 = setInterval(function(){ //change_motor('RIGHTBACKWARD'); //}, 3000); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#tops').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('tops'); //ff1 = setInterval(function(){ //change_motor('RIGHTBACKWARD'); //}, 3000); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#topr').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('topr'); //ff1 = setInterval(function(){ //change_motor('RIGHTBACKWARD'); //}, 3000); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); //clearInterval(ff1); }); $('#l').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('L'); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); change_motor2(); }); $('#r').bind('touchstart', function() { // 押されたとき if(motor == 'STOP') { $(this).addClass('ledon'); change_motor('R'); } }).bind('touchend', function() { // 離したとき $(this).removeClass('ledon'); //change_motor('STOP'); change_motor2(); }); }); ``` ``` #!/usr/bin/python3 #! -*- coding: utf-8 -*- import time import cgi import Adafruit_PCA9685 import RPi.GPIO as GPIO import sys GPIO.setmode(GPIO.BCM) LED_1 = 18 LED_2 = 23 GPIO.setup(LED_1, GPIO.OUT) GPIO.setup(LED_2, GPIO.OUT) #led = GPIO.PWM(LED_1,50) #led2 = GPIO.PWM(LED_2,50) #light = 0 form = cgi.FieldStorage() recieve = form.getvalue('name') pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(60) a = 370 b = 360 c = 380 d = 350 e = 380 f = 370 g = 370 h = 390 i = 300 j = 400 k = 300 l = 420 if recieve == 'hhhh': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c <= 450): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) #time.sleep(3) while(c >= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a >= 300): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a <= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) print('Content-type: text/html\n') print(recieve) print('ff') elif recieve == 'jjjj': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c >= 310): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 #e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) while(c <= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 #e = e - 2 time.sleep(0.005) print('Content-type: text/html\n') print(recieve) print("r") elif recieve == 'kkkk': while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a <= 440): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 #e = e - 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a >= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 #e = e + 2 time.sleep(0.005) print('Content-type: text/html\n') print(recieve) print('l') elif recieve == 'iiii': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c >= 310): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) #time.sleep(3) while(c <= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a <= 440): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a >= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) print('Content-type: text/html\n') print(recieve) print('bk') elif recieve == "topl": pwm.set_pwm(11, 0, 300) print('Content-type: text/html\n') print(recieve) print('l') elif recieve == "tops": pwm.set_pwm(11, 0, 420) print('Content-type: text/html\n') print(recieve) print('s') elif recieve == "topr": pwm.set_pwm(11, 0, 540) print('Content-type: text/html\n') print(recieve) print('r') elif recieve == 'qqqq': GPIO.output(LED_1,GPIO.LOW) GPIO.output(LED_2,GPIO.LOW) pwm.set_pwm(11, 0, 370) while(e <= 480): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(4, 0, e) e = e + 2 time.sleep(0.005) time.sleep(1) while(f <= 600): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(5, 0, f) #pwm.set_pwm(4, 0, e) #pwm.set_pwm(5, 0, f) #pwm.set_pwm(6, 0, g) f = f + 2 #g = g - 2 #e = e - 2 time.sleep(0.005) time.sleep(0.5) while(j <= 500): pwm.set_pwm(9, 0, j) j = j + 2 time.sleep(0.005) time.sleep(3) #while(l >= 320): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(11, 0, 300) GPIO.output(LED_1,GPIO.HIGH) GPIO.output(LED_2,GPIO.HIGH) time.sleep(5) GPIO.output(LED_1,GPIO.LOW) GPIO.output(LED_2,GPIO.LOW) pwm.set_pwm(0, 0, a) pwm.set_pwm(1, 0, b) pwm.set_pwm(2, 0, c) pwm.set_pwm(3, 0, d) pwm.set_pwm(4, 0, 380) pwm.set_pwm(5, 0, 370) pwm.set_pwm(6, 0, g) pwm.set_pwm(7, 0, 390) pwm.set_pwm(8, 0, i) pwm.set_pwm(9, 0, 400) pwm.set_pwm(10, 0, k) pwm.set_pwm(11, 0, l) print('Content-type: text/html\n') print(recieve) print('1') elif recieve == 'mmmm': #2 pwm.set_pwm(11, 0, l) GPIO.output(LED_1,GPIO.LOW) GPIO.output(LED_2,GPIO.LOW) while(e >= 280): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(4, 0, e) e = e - 2 time.sleep(0.005) time.sleep(1) while(g >= 140): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(6, 0, g) #pwm.set_pwm(4, 0, e) #pwm.set_pwm(5, 0, f) #pwm.set_pwm(6, 0, g) g = g - 2 #g = g - 2 #e = e - 2 time.sleep(0.005) time.sleep(0.5) while(k >= 150): pwm.set_pwm(10, 0, k) k = k - 2 time.sleep(0.005) time.sleep(3) #while(l >= 320): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(11, 0, 540) GPIO.output(LED_1,GPIO.HIGH) GPIO.output(LED_2,GPIO.HIGH) time.sleep(5) GPIO.output(LED_1,GPIO.LOW) GPIO.output(LED_2,GPIO.LOW) pwm.set_pwm(0, 0, a) pwm.set_pwm(1, 0, b) pwm.set_pwm(2, 0, c) pwm.set_pwm(3, 0, d) pwm.set_pwm(4, 0, 380) pwm.set_pwm(5, 0, 370) pwm.set_pwm(6, 0, 370) pwm.set_pwm(7, 0, 390) pwm.set_pwm(8, 0, 300) pwm.set_pwm(9, 0, 400) pwm.set_pwm(10, 0, 300) pwm.set_pwm(11, 0, l) print('Content-type: text/html\n') print(recieve) print('2') elif recieve == 'oooo': #3 num = 0 while(n >= 340): pwm.set_pwm(1, 0, n) pwm.set_pwm(3, 0, t) time.sleep(0.0001) n = n - 1 t = t - 1 while(num <= 3): num = num + 1 while(c >= 130): pwm.set_pwm(6, 0, c) pwm.set_pwm(7, 0, d) time.sleep(0.0001) c = c - 1 d = d + 1 while(c <= 230): pwm.set_pwm(6, 0, c) pwm.set_pwm(7, 0, d) time.sleep(0.0001) c = c + 1 d = d - 1 while(n <= 440 ): pwm.set_pwm(1, 0, n) pwm.set_pwm(3, 0, t) time.sleep(0.0001) n = n + 1 t = t + 1 print('Content-type: text/html\n') print(recieve) print('3') elif recieve == 'zzzz': #4 num = 0 while(n <= 540): pwm.set_pwm(1, 0, n) pwm.set_pwm(3, 0, t) time.sleep(0.0001) n = n + 1 t = t + 1 while(num <= 3): num = num + 1 while(c >= 130): pwm.set_pwm(6, 0, c) pwm.set_pwm(7, 0, d) time.sleep(0.0001) c = c - 1 d = d + 1 while(c <= 230): pwm.set_pwm(6, 0, c) pwm.set_pwm(7, 0, d) time.sleep(0.0001) c = c + 1 d = d - 1 while(n >= 440 ): pwm.set_pwm(1, 0, n) pwm.set_pwm(3, 0, t) time.sleep(0.0001) n = n - 1 t = t - 1 print('Content-type: text/html\n') print(recieve) print('4') elif recieve == 'gggg': GPIO.output(LED_1,GPIO.HIGH) GPIO.output(LED_2,GPIO.HIGH) #while(light <= 100): #led.ChangeDutyCycle(right) #led2.ChangeDutyCycle(right) #light = light + 1 #time.sleep(0.05) elif recieve == 'dddd': GPIO.output(LED_1,GPIO.LOW) GPIO.output(LED_2,GPIO.LOW) #while(light >= 0): #led.ChangeDutyCycle(right) #led2.ChangeDutyCycle(right) #light = light - 1 #time.sleep(0.05) elif recieve == 'ssss': #GPIO.output(MOTOR_A1,GPIO.LOW) #GPIO.output(MOTOR_A2,GPIO.LOW) #GPIO.output(MOTOR_A3,GPIO.LOW) #GPIO.output(MOTOR_A4,GPIO.LOW) #pwm.set_pwm(0, 0, 375) #pwm.set_pwm(1, 0, 375) #pwm.set_pwm(2, 0, 375) #pwm.set_pwm(3, 0, 375) pass print('st') ``` スマホでテスト。 @[twitter](https://twitter.com/ketunorobio/status/1578986569993945088?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1578986569993945088%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) ### アナログコントローラー(micropython) アナログコントローラーにはM5stickCのJoyCを使いました。 当初はbleで接続する予定でしたが、micropythonのbleのライブラリであるubluetoothがm5stickcのmicropythonファームウェアでは利用出来ず、断念してUDPで接続させています。(ESP32のmicropythonファームウェアを入れたらubluetoothライブラリが使用できましたが、代わりにJoyC等m5stack関連のライブラリが使用できない。) ※あやまってmain.pyプログラムをdeleteしてしまいました(;^ω^)後日改めて掲載します。 ### RaspberryPi側(python) ``` from socket import socket, AF_INET, SOCK_DGRAM import time import Adafruit_PCA9685 import RPi.GPIO as GPIO import sys import threading GPIO.setmode(GPIO.BCM) LED_1 = 18 LED_2 = 23 GPIO.setup(LED_1, GPIO.OUT) GPIO.setup(LED_2, GPIO.OUT) #led = GPIO.PWM(LED_1,50) #led2 = GPIO.PWM(LED_2,50) led = 0 led2 = 0 #led.start(0) #led2.start(0) right = 0 pwm = Adafruit_PCA9685.PCA9685() pwm.set_pwm_freq(60) a = 370 b = 360 c = 380 d = 350 e = 380 f = 370 g = 370 h = 390 i = 300 j = 400 k = 300 l = 420 HOST = "ローカルIP" PORT = 5000 s = socket(AF_INET, SOCK_DGRAM) s.bind((HOST, PORT)) msg = "none" def recieve(): global msg while True: msg, address = s.recvfrom(8192) #print(f"message: {msg}\nfrom: {address}") msg = msg.decode() print(msg) time.sleep(0.1) th = threading.Thread(target=recieve) th.start() while True: try: if msg == 'f': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c <= 450): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) #time.sleep(3) while(c >= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a >= 300): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a <= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) elif msg == 'r': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c >= 310): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 #e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) while(c <= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 #e = e - 2 time.sleep(0.005) elif msg == 'l': while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a <= 440): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 #e = e - 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a >= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) #pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 #e = e + 2 time.sleep(0.005) elif msg == 'b': while(d >= 300): pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(c >= 310): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) #time.sleep(3) while(b <= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d + 2 b = b + 2 time.sleep(0.005) #time.sleep(3) while(c <= 380): #sev.position(2, c) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(2, 0, c) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) c = c + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b <= 410): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) b = b + 2 d = d + 2 time.sleep(0.005) #time.sleep(3) while(a <= 440): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a + 2 f = f - 2 g = g - 2 e = e - 2 time.sleep(0.005) #time.sleep(3) while(b >= 360): #sev.position(3, d) #sev.position(1, b) pwm.set_pwm(1, 0, b) pwm.set_pwm(3, 0, d) d = d - 2 b = b - 2 time.sleep(0.005) #time.sleep(3) while(a >= 370): #sev.position(0, a) #sev.position(4, e) #sev.position(5, f) #sev.position(6, g) pwm.set_pwm(0, 0, a) pwm.set_pwm(4, 0, e) pwm.set_pwm(5, 0, f) pwm.set_pwm(6, 0, g) a = a - 2 f = f + 2 g = g + 2 e = e + 2 time.sleep(0.005) elif msg == "hl": if l >= 300: l = l - 2 pwm.set_pwm(11, 0, l) time.sleep(0.005) elif msg == "hr": if l <= 540: l = l + 2 pwm.set_pwm(11, 0, l) time.sleep(0.005) elif msg == "hlf": if f >= 140: f = f - 2 pwm.set_pwm(5, 0, f) time.sleep(0.005) elif msg == "hlb": if f <= 600: f = f + 2 pwm.set_pwm(5, 0, f) time.sleep(0.005) elif msg == "hrf": if g <= 600: g = g + 2 pwm.set_pwm(6, 0, g) time.sleep(0.005) elif msg == "hrb": if g >= 140: g = g - 2 pwm.set_pwm(6, 0, g) time.sleep(0.005) elif msg == "hlup": if h <= 600: h = h + 2 pwm.set_pwm(7, 0, h) time.sleep(0.005) elif msg == "hldown": if h >= 390: h = h - 2 pwm.set_pwm(7, 0, h) time.sleep(0.005) elif msg == "hrup": if i >= 90: i = i - 2 pwm.set_pwm(8, 0, i) time.sleep(0.005) elif msg == "hrdown": if i <= 300: i = i + 2 pwm.set_pwm(8, 0, i) time.sleep(0.005) elif msg == "el": if e <= 480: e = e + 1 pwm.set_pwm(4, 0, e) time.sleep(0.005) elif msg == "er": if e >= 280: e = e - 1 pwm.set_pwm(4, 0, e) time.sleep(0.005) elif msg == "on": led = GPIO.PWM(LED_1,50) led2 = GPIO.PWM(LED_2,50) led.start(0) led2.start(0) while(right <= 100): led.ChangeDutyCycle(right) led2.ChangeDutyCycle(right) right = right + 1 time.sleep(0.05) right = right - 1 elif msg == "set": pwm.set_pwm(0, 0, 370) pwm.set_pwm(1, 0, 360) pwm.set_pwm(2, 0, 380) pwm.set_pwm(3, 0, 350) pwm.set_pwm(4, 0, 380) pwm.set_pwm(5, 0, 370) pwm.set_pwm(6, 0, 370) pwm.set_pwm(7, 0, 390) pwm.set_pwm(8, 0, 300) pwm.set_pwm(9, 0, 400) pwm.set_pwm(10, 0, 300) pwm.set_pwm(11, 0, 420) time.sleep(1) elif msg == "off": while(right >= 0): led.ChangeDutyCycle(right) led2.ChangeDutyCycle(right) right = right - 1 time.sleep(0.05) right = right + 1 led.stop() led2.stop() time.sleep(0.001) except: s.close() ``` ジョイコンでテスト。 @[twitter](https://twitter.com/ketunorobio/status/1580511186679799809) ## 電源ボタンの追加 @[twitter](https://twitter.com/ketunorobio/status/1581110589815824385?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1581110589815824385%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) ## 完成 @[twitter](https://twitter.com/ketunorobio/status/1581549942392266752?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1581549942392266752%7Ctwgr%5E2a7401420d31c2d9906a11886ac66be9487376e7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fe382b5e383bce3839c11e5808be381a8raspberrypi-zero2we381a7e5a49ae996a2e7af802e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e38292e4bd9ce381a3%2F) とりあえず仮で完成としますが、また機能追加すればここでまとめたいと思います。