开源六轴协作机械臂myCobot280实现交互式乘法!让学习充满乐趣

news2024/12/25 12:20:33

本文经作者Fumitaka Kimizuka 授权我们翻译和转载。
原文链接:myCobotに「頷き」「首振り」「首傾げ」をしてもらう 🤖 - みかづきブログ・カスタム

引言

Fumitaka Kimizuka 创造了一个乘法表系统,帮助他的女儿享受学习乘法表的乐趣。她可以口头回答乘法问题,显示的数字就是乘积。如果她回答正确,myCobot 就会点头;如果她回答错误,myCobot 就会做出不同的动作。以下是作者对该系统开发过程的记录。

🤖

https://twitter.com/i/status/1793416553867706459

在实施这一机制时,我用 Node.js 编写了一个程序,让 myCobot "点头"、"摇头 "和 "歪头"。

https://twitter.com/i/status/1780785823220224188

这是我将其与 LINE Bot 相关联时创建的程序的改进版。

准备工作

首先,按照以下步骤使 myCobot 可以通过 Python 运行。

然后,使用 Node.js 和 Express 架设网络服务器。虽然你也可以使用 Python 设置网络服务器,但以我的技术水平,Node.js 对我来说更快。因此,我使用 Node.js 和 python-shell 来控制 myCobot。

python-shell - npm

.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
);

通过创建一个 "move "函数,该函数可以接受 LED 矩阵颜色、关节角度和驱动时间等参数,因此变得非常方便。

实施:

对于点头、摇头和歪头,请使用之前创建的`move`函数。

// 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();
    }
  });
}

我是这样实现的,接下来,通过 Web API 调用点头、摇头和歪头动作。

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 矩阵的颜色也在悄然改变。

目前看起来是这样的,但如果再调整一下,效果可能会更好,尤其是头部的倾斜动作。

Github 存储库

https://github.com/kimizuka/mycobot-express/tree/example/timas-table

总结

我们非常感谢 Fumitaka Kimizuka 允许我们分享如此出色的技术案例研究。我们希望在阅读本文后,您能从中受到启发,创造出更多有趣而实用的项目。如果您有类似的想法或作品,请与我们分享,让我们共同推动技术进步和创新!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1905883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【open3d专栏】利用PCA计算狭长点云的主方向

在点云处理中,PCA通常用于识别数据集中的主要方向,从而帮助理解数据的几何结构。 使用工具:python,open3d库 目的:计算狭长型点云的主方向 # -*- coding: utf-8 -*- """ Created on Sun Jul 7 11:50…

vb.netcad二开自学笔记9:界面之ribbon

一个成熟的软件怎么能没有ribbon呢&#xff0c;在前面的框架基础上再加个命令AddRibbon <CommandMethod("AddRibbon")> Public Sub AddRibbon() Dim ribbonControl As RibbonControl ComponentManager.Ribbon Dim tab As RibbonTab New RibbonTab() tab.Tit…

二手闲置平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;卖家管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;商品购买管理&#xff0c;商品配送管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&a…

新型水冷电阻设计-双面水冷电阻器

一款革命性的电阻器&#xff0c;专为低压和中压应用而设计&#xff0c;尤其是汽车、牵引或船舶系统中的恶劣条件。 EAK采用先进材料制造&#xff0c;采用专利设计&#xff0c;将电阻元件与水基冷却液封装并完全分离&#xff0c;为水冷应用提供模块化、轻量级、小容量、高功率解…

Yet Another Permutation Constructive

这道题目不用写&#xff0c;因为必须要求用kotlin语言 讲一下我做这道题目的过程 我最开始正着想&#xff0c;如果\(k\)比较大的话&#xff0c;我们就想一次删的数少一点&#xff0c;所以考虑一次操作有哪些数被保留&#xff0c;于是我们发现&#xff0c;原序列的极大值点会被保…

从零开始的python学习生活1

python函数的对返回值 本来多个return是不行的 这种语法就能接受多个返回值 def hanshu():return 1,"hello",True x,y,z hanshu() print(x) print(y) print(z)函数的多种传参方式 提前说明白了顺序就无所谓了 关键字传递一个传递参数&#xff0c;一个传递键值…

【数据结构与算法】详解二叉树 上:理论篇——二叉树的基本概念与性质

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​​ 目录 一、树的概念 &#x1f343;树的定义 &#x1f343;树的特点 &#x1f343;树的相…

Dify v0.6.9源码部署

一.前置条件 克隆Dify v0.6.9代码&#xff1a; git clone https://github.com/langgenius/dify.git在启用业务服务之前&#xff0c;需要先部署 PostgresSQL / Redis / Weaviate&#xff08;如果本地没有的话&#xff09;&#xff0c;可以通过以下命令启动&#xff1a; cd do…

C#描述-计算机视觉OpenCV(5):直方图算法

C#描述-计算机视觉OpenCV&#xff08;5&#xff09;&#xff1a;直方图算法 前文链接图像直方图灰度直方图的计算灰度直方图的绘制BGR三通道的直方图直方图的均衡化算法相似图像检测 前文链接 文中没提到的东西&#xff0c;很可能都在前文描述过 C#描述-计算机视觉OpenCV&…

[AI 大模型] OpenAI ChatGPT

文章目录 ChatGPT 简介ChatGPT 的模型架构ChatGPT的发展历史节点爆发元年AI伦理和安全 ChatGPT 新技术1. 技术进步2. 应用领域3. 代码示例4. 对话示例 ChatGPT 简介 ChatGPT 是由 OpenAI 开发的一个大型语言模型&#xff0c;基于GPT-4架构。它能够理解和生成自然语言文本&…

CentOS7安装、CentOS7修改root密码

目录 1 下载镜像 2 使用VMware新建一个虚拟机 3 centos7修改root密码 1 下载镜像 开源镜像站-阿里云centos-7.9.2009-isos-x86_64安装包是阿里云官方提供的开源镜像免费下载服务,每天下载量过亿,阿里巴巴开源镜像站为包含centos-7.9.2009-isos-x86_64安装包的几百个操作系统…

移动校园(2):express构建服务器,小程序调用接口,展示数据

express做服务器框架&#xff0c;mssql连接数据库&#xff0c;uni-request调用接口 这是文件夹目录 然后是index.js内容 const expressrequire(express) const appexpress() const uniRouterrequire("./uniRouter") const config{user:sa,password:123456,server:l…

汉中茗茶小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;基础数据管理&#xff0c;茶叶管理&#xff0c;论坛管理&#xff0c;公告管理&#xff0c;茗茶历史管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;茗茶信息&#xf…

正则表达式 先行断言 \S {} 示例

目录 数据准备一. 先行断言1.1 正向先行断言1.2 负向先行断言 二. 配合 {} 和 \S 使用2.1 匹配一个任意非空白字符2.2 匹配任意多个非空白字符2.3 匹配3个非空白字符2.4 匹配至少3个非空白字符2.5 匹配0~3个非空白字符 数据准备 ⏹文件1 0561-10 AAA 123 dfg 345 sss 0561-2…

2008-2021年各省份高技术产业科研与发展(RD)活动情况数据

R&D&#xff08;研究与发展&#xff09;活动是推动国家和公司技术创新和经济增长的关键因素。以下是对各省份高技术产业科研与发展&#xff08;R&D&#xff09;活动情况数据的介绍&#xff1a; 数据简介 定义&#xff1a;R&D指在产品开发、工艺设计、生产技术改进…

阿尔泰科技与西安交通大学陕西省某技术重点实验室共谋未来!

近日&#xff0c;阿尔泰科技的电子工程师&#xff08;熊工&#xff09;应邀前往西安交通大学陕西省某技术重点实验室&#xff0c;参与课题组项目的测试与调试工作。此次合作不仅成功推动了项目的进展&#xff0c;还为未来的深入合作奠定了坚实基础。 阿尔泰科技作为领先的测控技…

Flink SQL kafka连接器

版本说明 Flink和kafka的版本号有一定的匹配关系&#xff0c;操作成功的版本&#xff1a; Flink1.17.1kafka_2.12-3.3.1 添加kafka连接器依赖 将flink-sql-connector-kafka-1.17.1.jar上传到flink的lib目录下 下载flink-sql-connector-kafka连接器jar包 https://mvnreposi…

AI教你如何系统的学习Python

Python学习计划 第一阶段&#xff1a;Python基础&#xff08;1-2个月&#xff09; 目标&#xff1a;掌握Python的基本语法、数据类型、控制结构、函数、模块和包等。 学习Python基本语法&#xff1a;包括变量、数据类型&#xff08;整数、浮点数、字符串、列表、元组、字典、…

Java求解百钱买百鸡问题(课堂实例2)

目录 &#x1f495;&#x1f495;引言&#x1f495;&#x1f495; &#x1f60d;&#x1f60d;点关注编程梦想家&#xff08;大学生版&#xff09;-CSDN博客不迷路&#x1f495;&#x1f495; 一、问题背景----百鸡百钱_百度百科 (baidu.com) &#x1d465;&#x1d466;&a…

颍川韩氏始祖,归顺大汉的弓高侯

弓高侯&#xff0c;听起来十分不顺当&#xff0c;像是域外来音似的。本人的名字更另类——颓当&#xff0c;词典中甚至找不到。然而&#xff0c;弓高曾经是河北的一个县名——弓高县&#xff0c;颓当曾经是匈奴的一个城——颓当城&#xff0c;这两个地名已经不存在了&#xff0…