This article has been authorized by the author Fumitaka Kimizuka for us to translate and republish.
Original link:https://blog.kimizuka.org/entry/2024/05/24/234500
IntroductionFumitaka Kimizuka created a multiplication table system to help his daughter enjoy learning the multiplication tables. She can verbally answer the multiplication problems, with the displayed numbers being the products. If she answers correctly, myCobot will nod; if she answers incorrectly, myCobot will perform a different action. Below is the author's record of the development process for this system.
When implementing this mechanism, I wrote a program in Node.js to make myCobot "nod, " "shake its head, " and "tilt its head."
This is an improved version of the program I created when I associated it with the LINE Bot.
Preparation:First, follow these steps to make myCobot operable from Python.
https://blog.kimizuka.org/entry/2021/08/10/131812
Then, set up a web server using Node.js and Express. Although you could set up the web server using Python, Node.js is faster for me given my skill set. Therefore, I am using Node.js with python-shell to control myCobot.
https://www.npmjs.com/package/python-shell
.env# Specify the USB port to which myCobot is connected
MY_COBOT_PORT=/dev/cu.XXXXXXXX
app.js (Excerpt)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 matrix colors (RGB)
[0, 0, 0, 0, 0, 0], // Angles of myCobot's joints (degrees)
200
);
By creating a `move` function that can take arguments for the LED matrix colors, joint angles, and driving time, it becomes very convenient.
Implementation:For nodding, shaking its head, and tilting its head, use the `move` function created earlier.
// Nodding
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();
}
});
}
// Shaking its head
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();
}
});
}
// Tilting its head
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();
}
});
}
I implemented it in this manner.
Next, make the nodding, head shaking, and head tilting actions callable via a Web API.
app.jsrequire('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');
With this setup,
A POST request to `http://localhost:3000/yes` will make it nod.
A POST request to `http://localhost:3000/no` will make it shake its head.
A POST request to `http://localhost:3000/hmm` will make it tilt its head.
will execute the respective actions.
DEMONodding
Shaking its head
Tilting its head
The LED matrix colors are also being changed quietly.
For now, it looks like this, but with a bit more adjustment, it could be even better, especially for the head tilting action.
Github Repositoryhttps://github.com/kimizuka/mycobot-express/tree/example/timas-table
SummaryWe appreciate Fumitaka Kimizuka for granting us permission to share such an excellent technical case study. We hope that after reading this article, you will be inspired to create more interesting and practical projects. If you have similar ideas or works, please share them with us so we can collectively drive technological progress and innovation.
Comments
Please log in or sign up to comment.