🤖
娘に九九のことを好きになってもらえたら良いなと思い、「表示された数字が積になる九九を口頭で答える仕組み」をつくりました。
— 君塚史高 (@ki_230) 2024年5月22日
正解するとmyCobotが頷いてくれます。 pic.twitter.com/2X6w4uN04F
こちらの仕組みを実装する時に、myCobotに「頷き」「首振り」「首傾げ」をしてもらうプログラムをNode.jsで書きました。
myCobotをLINE Botから操作できるようにしてみました。リッチメニューから「頷き」と「首振り」を指示できます。 pic.twitter.com/r4IMgIRWOM
— 君塚史高 (@ki_230) 2024年4月18日
LINE Botと連想した際に作ったプログラムの改良版です。
準備
まずは、こちらの手順でmyCobotをPythonから動かせるようにします。
そして、Node.jsとExpressを使ってWebサーバを立てます。
Pythonを使ってWebサーバを立てても良いのですが、僕のスキルセット的にNode.jsの方が早いので、Node.jsからpython-shellを使ってmyCobotを動かしています。
.env
#myCobotが接続されているUSBポートを記入する MY_COBOT_PORT=/dev/cu.XXXXXXXX
app.js(抜粋)
const express = require('express'); const express = require('express'); const { PythonShell } = require('python-shell'); const app = express(); const http = require('http').Server(app); app.use(express.json()); app.use('/', express.static(`${ __dirname }/public`)); async function move(color = [255, 255, 255], angles = [0, 0, 0, 0, 0, 0], interval = 200) { return new Promise((resolve, reject) => { PythonShell.runString( `from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').set_color(${ color }); from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').send_angles([${ angles }], ${ duration })`, null ).then(() => { setTimeout(() => resolve(), interval); }).catch(() => { reject(); }); }); } move( [255, 255, 255], // LEDマトリクスの色(RGB) [0, 0, 0, 0, 0, 0], // myCobotの関節の角度(deg) 200 );
という感じで、LEDマトリクスの色、関節の角度、駆動時間を引数で渡せるmove関数を作っておくと便利です。
実装
頷き、首振り、首傾げですが、先ほど作成したmove関数を使って、
// 頷き async function doYes() { return new Promise(async (resolve, reject) => { const interval = 200; try { await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval); resolve(); } catch (err) { console.error(err); reject(); } }); } // 首振り async function doNo() { return new Promise(async (resolve, reject) => { const interval = 400; try { await move([255, 0, 0], [0, 0, 0, 0, 45, 0], interval / 2); await move([255, 0, 0], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, 0, 0], interval / 2); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval / 2); resolve(); } catch (err) { console.error(err); reject(); } }); } // 首傾げ async function doHmm() { return new Promise(async (resolve, reject) => { const interval = 400; try { await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval / 2); await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, 0, 0], interval / 2); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval / 2); resolve(); } catch (err) { console.error(err); reject(); } }); }
という形で実装してみました。
そして、頷き、首振り、首傾げをWebAPIから呼び出せるようにします。
app.js(全文)
require('dotenv').config(); const express = require('express'); const { PythonShell } = require('python-shell'); const app = express(); const http = require('http').Server(app); const PORT = 3000; app.use(express.json()); app.use('/', express.static(`${ __dirname }/public`)); app.post('/yes', (req, res) => { doYes(); res.send(200); }); app.post('/no', (req, res) => { doNo(); res.send(200); }); app.post('/hmm', (req, res) => { doHmm(); res.send(200); }); // https://www.elephantrobotics.com/wp-content/uploads/2021/03/myCobot-User-Mannul-EN-V20210318.pdf async function move(color = [255, 255, 255], angles = [0, 0, 0, 0, 0, 0], interval = duration) { return new Promise((resolve, reject) => { PythonShell.runString( `from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').set_color(${ color }); from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').send_angles([${ angles }], ${ duration })`, null ).then(() => { setTimeout(() => resolve(), interval); }).catch(() => { reject(); }); }); } async function doYes() { return new Promise(async (resolve, reject) => { const interval = 200; try { await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 45, 0, 0], interval); await move([0, 0, 255], [0, 0, 0, 0, 0, 0], interval); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval); resolve(); } catch (err) { console.error(err); reject(); } }); } async function doNo() { return new Promise(async (resolve, reject) => { const interval = 400; try { await move([255, 0, 0], [0, 0, 0, 0, 45, 0], interval / 2); await move([255, 0, 0], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 0], [0, 0, 0, 0, 0, 0], interval / 2); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval / 2); resolve(); } catch (err) { console.error(err); reject(); } }); } async function doHmm() { return new Promise(async (resolve, reject) => { const interval = 400; try { await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval / 2); await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, 45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, -45, 0], interval); await move([255, 0, 255], [0, 0, 0, 0, 0, 0], interval / 2); await move([255, 255, 255], [0, 0, 0, 0, 0, 0], interval / 2); resolve(); } catch (err) { console.error(err); reject(); } }); } try { doYes(); } catch(err) { console.error(err); } http.listen(PORT, '0.0.0.0');
これで、
- http://localhost:3000/yes にPOSTリクエストで頷き
- http://localhost:3000/no にPOSTリクエストで首振り
- http://localhost:3000/hmm にPOSTリクエストで首傾げ
を実行します。
DEMO
頷き
首振り
首傾げ
ひっそりとLEDマトリクスの色も変更しています。
一旦、こんな感じですが、もうちょっと調整すると、もっと良い感じになりそうです。特に首傾げ。