分享Arduino驱动的机械臂,附带3D打印模型,软件控制方案
本帖最后由 sczhf 于 2022-8-19 15:27 编辑## 控制重点
1. 使用物联网开发工具 Smart,通过 Modbus TCP 通讯协议,利用网络发送指令给 Arduino mega2560 开发板
2. 使用开源的 Modbus TCP 程序库,串接 Arduino mega2560、CNC Shield V3、A4988,并以此控制 42 步进马达。
3. 连接电脑上的摄象头,直接拍摄平移式机械臂,即时运动影象。
## 运行展示
点击下方视频链接查看运行的效果:
* https://www.ixigua.com/7133447547426701831
## 使用控制设备
| 序号 | 零件名称 | 数量 |
| ---- | --------------------------- | ---- |
| 1 | Arduino Mega 2560 开发板 | 2 |
| 2 | 42 步进电机 | 4 |
| 3 | 270° 舵机 | 1 |
| 4 | CNC Shield V3 | 2 |
| 5 | A4988 步进电机驱动器 | 4 |
| 6 | W5100 EtherNet 网络扩展板| 2 |
| 7 | 网络摄像头(罗技C270i) | 1 |
## 使用工业通讯协定
Modbus TCP,可换用 Modbus RTU、OPC UA、MQTT、RestAPI、WebSocket。
## 使用开发软体
Smart物联网的精灵。软件控制的设计方案是出自于此。
## 零件连线
基本的零件连线示意图如下。由于一块CNC Shield 最多支持三块A4988的独立驱动,故此处使用两块板来实现相应的功能。舵机用于控制爪子的开合,其余的步进马达分别控制四轴方向上的运动。
## 外壳打印
使用3D打印制作外壳的材料。所需的素材文件会在下方的链接中提供。外壳打印完成后进行组装。
## 参考资料
上述提到所需的相关文件已放在Gitee。
* https://gitee.com/isoface-iot/Smart/tree/master/demo/iot/s-eq-dem-2201_translation_robotic_arm
其中有包含一个后缀名为 `sdb` 的文件,这个文件是软件控制方案的工程文件。需使用物联网开发工具 Smart 打开。可在Gitee 项目中获取下载链接。
* https://gitee.com/isoface-iot/Smart
欢迎大家来学习交流,如果有什么不明白的地方可以给我留言,我看到了会回复。 本帖最后由 sujieluck 于 2022-8-24 09:01 编辑
为了便于大家阅读理解,特意把程序放上来,希望贴主理解。其中一个程序
#include <SPI.h>
#include <Ethernet.h>
#include <Servo.h>
// 配合单轴采用之程序 以补足 CNC Shiel 只能支持 3轴的问题
// 采用 MyArduinoProjects Modbus TCP 程序库
// http://myarduinoprojects.com/modbus.html
#include "MgsModbus.h"
MgsModbus Mb;
// 设置网络IP位址 (网络扩充卡 MAC 可自行修改 +1 避免冲突)
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB6 };
IPAddress ip(192, 168, 3, 162);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
int pos = 0; // 设置 Servo 位置的变量
Servo myservo; // 定义舵机变量
unsigned char i=0;
#define EN 8 // 步进电机使能端,低电平有效
#define X_DIR 5 // A轴 步进电机方向控制
#define X_STP 2 //A 轴 步进控制
int arma=0; // A轴行程 150mm 水平前进初始位置 所以最大可以走 600步 ,初始值取原点,也就是爪子最接近马达处
int larma=0;
// #include <Stepper.h>
#define STEPS 200//定义步进马达每圈的步数
//steps:代表马达转完一圈需要多少步数。如果马达上有标示每步的度数,
//将360除以这个角度,就可以得到所需要的步数(例如:360/1.8=200)。
//螺杆行程是 2mm 代表转一圈 移动的距离
/*
//函数:step 功能:控制步进电机方向,步数。
//参数:dir 方向控制, dirPin对应步进电机的DIR引脚,stepperPin 对应步进电机的step引脚, steps 步进的步数
//无返回值
*/
void step(boolean dir, byte dirPin, byte stepperPin, int steps)
{
digitalWrite(dirPin, dir);
delay(50);
for (int i = 0; i < steps; i++) {
digitalWrite(stepperPin, HIGH);
delayMicroseconds(1500);
digitalWrite(stepperPin, LOW);
delayMicroseconds(1350);
}
}
void stepZ(boolean dir, byte dirPin, byte stepperPin, int steps) // 转盘转动速度太快会抖动 所以放慢速度 用单独的函数
{
digitalWrite(dirPin, dir);
delay(50);
for (int i = 0; i < steps; i++) {
digitalWrite(stepperPin, HIGH);
delayMicroseconds(12000);
digitalWrite(stepperPin, LOW);
delayMicroseconds(10800);
}
}
void setup(){
Serial.begin(9600);
Ethernet.begin(mac, ip, gateway, subnet); //启动网络
Serial.println("网络已经开通");
//设置要使用的寄存器位址
//0 1 2 3 4 是 Holding 寄存器的顺序,其位址分别是10000,10001,10002,10003,10004
// 添加寄存器 mb.MbData(i);
Mb.MbData = 0; // A轴行程 160mm 水平前进初始位置 转 200步移动 2mm 取中间值
pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT); //将步进电机用到的 IO 脚位设置成输出
pinMode(EN, OUTPUT);
digitalWrite(EN, LOW); // 开启 CNC 开发板的马达启动功能
}
void loop(){
// 读取数位寄存器的数值,
arma=Mb.MbData; // A轴 数值变大 爪子往前
if (arma!=larma){
if (arma<larma){
step(true, X_DIR, X_STP, (larma-arma)); // A轴电机往后
}
else {
step(false, X_DIR, X_STP, (arma-larma)); // A轴电机往前
}
larma=arma;
}
Mb.MbsRun(); //调用 Modbus
}
#include <SPI.h>
#include <Ethernet.h>
#include <Servo.h>
// 采用 MyArduinoProjects Modbus TCP 程序库
// http://myarduinoprojects.com/modbus.html
#include "MgsModbus.h"
MgsModbus Mb;
// 设置网络IP位址 (网络扩充卡 MAC 可自行修改 +1 避免冲突)
byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB5 };
IPAddress ip(192, 168, 3, 161);
IPAddress gateway(192, 168, 3, 1);
IPAddress subnet(255, 255, 255, 0);
int pos = 0; // 设置 Servo 位置的变量
Servo myservo; // 定义舵机变量
unsigned char i=0;
#define EN 8 // X,Y,Z轴步进电机使能端,低电平有效
#define X_DIR 5 // X轴 步进电机方向控制
#define Y_DIR 6 // y轴 步进电机方向控制
#define Z_DIR 7 // z轴 步进电机方向控制
#define X_STP 2 // x轴 步进控制
#define Y_STP 3 // y轴 步进控制
#define Z_STP 4 // z轴 步进控制
#define AEN 28 // A轴步进电机使能端,低电平有效
#define A_DIR 26 // A轴 步进电机方向控制
#define A_STP 24 // A轴 步进控制
int armx=0;
int army=0;
int armz=450;
int arma=0;
int armc=60;
int larmx=0;
int larmy=0;
int larmz=450;
int larma=0;
int larmc=60;
// #include <Stepper.h>
#define STEPS 200//定义步进马达每圈的步数
//steps:代表马达转完一圈需要多少步数。如果马达上有标示每步的度数,
//将360除以这个角度,就可以得到所需要的步数(例如:360/1.8=200)。
//螺杆行程是 2mm 代表转一圈 移动的距离
/*
//函数:step 功能:控制步进电机方向,步数。
//参数:dir 方向控制, dirPin对应步进电机的DIR引脚,stepperPin 对应步进电机的step引脚, steps 步进的步数
//无返回值
*/
void step(boolean dir, byte dirPin, byte stepperPin, int steps)
{
digitalWrite(dirPin, dir);
delay(50);
for (int i = 0; i < steps; i++) {
digitalWrite(stepperPin, HIGH);
delayMicroseconds(1500);
digitalWrite(stepperPin, LOW);
delayMicroseconds(1350);
}
}
void stepZ(boolean dir, byte dirPin, byte stepperPin, int steps) // 转盘转动速度太快会抖动 所以放慢速度 用单独的函数
{
digitalWrite(dirPin, dir);
delay(50);
for (int i = 0; i < steps; i++) {
digitalWrite(stepperPin, HIGH);
delayMicroseconds(12000);
digitalWrite(stepperPin, LOW);
delayMicroseconds(10800);
}
}
void setup(){
Serial.begin(9600);
Ethernet.begin(mac, ip, gateway, subnet); //启动网络
Serial.println("网络已经开通");
//设置要使用的寄存器位址
//0 1 2 3 4 是 Holding 寄存器的顺序,其位址分别是10000,10001,10002,10003,10004
// 添加寄存器 mb.MbData(i);
Mb.MbData = 0; // X轴行程 300mm 水平前进初始位置 转 200步移动 2mm,所以最大可以走 6000步 ,初始值取原点,也就是水平平台最接近马达处
Mb.MbData = 0; // Y轴行程 210mm 往上初始位置转 200步移动 2mm,所以最大可以走 4200步 ,初始值取原点,也就是垂直平台最接近马达处
Mb.MbData = 450; // Z轴转盘初始位置 转360步 相当于转动 90度 Z轴可转动 180 度相当于 720步,初始值取中间值,90度,也就是爪子轴在中间
Mb.MbData = 0; // A轴 爪子延伸轴初始位置
Mb.MbData = 60; // 爪子初始位置爪子可开启最大转动步数为 180 因为开机会自动开到最大 所以设 0舵机最大旋转角度也只有 180度
myservo.attach(22); //定义舵机接口
pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT); //将步进电机用到的 IO 脚位设置成输出
pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);
pinMode(Z_DIR, OUTPUT); pinMode(Z_STP, OUTPUT);
pinMode(A_DIR, OUTPUT); pinMode(A_STP, OUTPUT);
pinMode(EN, OUTPUT);
digitalWrite(EN, LOW); // 开启 CNC 开发板的马达启动功能
pinMode(AEN, OUTPUT);
digitalWrite(AEN, LOW);
}
void loop(){
// 读取数位寄存器的数值,
armx=Mb.MbData; // X轴 数值变小 因为 Modbus 无法存负数所以中心点设为 45 以 X轴而言 数值变小往前
army=Mb.MbData; // Y轴 数值变小 Y轴 往上
armz=Mb.MbData; // Z轴 数值变小 转盘 往左
arma=Mb.MbData; // A轴
armc=Mb.MbData; // 0 爪子关 1 爪子开 开机时爪子会自动打开
if (armx!=larmx){
if (armx<larmx){
step(true, X_DIR, X_STP, (larmx-armx)); // X轴电机后退顺时旋转转1圈,200步为一圈
}
else {
step(false, X_DIR, X_STP, (armx-larmx)); // X轴电机後前
}
larmx=armx;
}
if (army!=larmy){
if (army<larmy){
step(false, Y_DIR, Y_STP, (larmy-army)); // Y轴电机往下
}
else {
step(true, Y_DIR, Y_STP, (army-larmy)); // Y轴电机往上
}
larmy=army;
}
if (armz!=larmz){
if (armz<larmz){
stepZ(false, Z_DIR, Z_STP, (larmz-armz)); //Z轴电机 往左旋转
}
else {
stepZ(true, Z_DIR, Z_STP, (armz-larmz)); //Z轴电机 往右旋转
}
larmz=armz;
}
if (arma!=larma){
if (arma<larma){
stepz(true, A_DIR, A_STP, (larma-arma)); // A轴电机往后
}
else {
stepz(false, A_DIR, A_STP, (arma-larma)); // A轴电机往前
}
larma=arma;
}
if (armc!=larmc){
if (armc<larmc){ //数值变大舵机顺时旋转 关闭爪子
for (pos = larmc; pos >= armc; pos -= 1)
{
myservo.write(pos); // 告诉 servo 走到 pos 的位置 舵机正旋转 关闭爪子 打开爪子
delay(5); // 等待 15ms 让 servo 走到指定位置
}
}
else
{ // 舵机逆时转 180度打开爪子
for (pos = larmc; pos <= armc; pos += 1)
{
myservo.write(pos); // 告诉 servo 走到 'pos' 的位置
delay(5); // 等待 15ms 让 servo 走到指定位置
}
}
larmc=armc;
}
/**
if (armc!=larmc){
if (armc==1){ //舵机顺时旋转 打开爪子
for (pos = 180; pos >= 0; pos -= 1) // 从 180 度旋转到 0 度,每次 1 度
{
myservo.write(pos); // 告诉 servo 走到 pos 的位置 舵机正旋转 打开爪子
delay(15); // 等待 15ms 让 servo 走到指定位置
}
}
if (armc==0){ // 舵机逆时转 180度爪子关
for (pos = 0; pos <= 180; pos += 1) // 从 0 度旋转到 180 度,每次 1 度
{
myservo.write(pos); // 告诉 servo 走到 'pos' 的位置
delay(15); // 等待 15ms 让 servo 走到指定位置
}
}
larmc=armc;
}
**/
Mb.MbsRun(); //调用 Modbus
}
void autorun()
{
step(false, X_DIR, X_STP, 240); // X轴电机 反转1圈,200步为一圈 方向往前
delay(1000);
step(false, Y_DIR, Y_STP, 240); // y轴电机 反转1圈,200步步为一圈 方向往上
delay(1000);
step(false, Z_DIR, Z_STP, 240); // z轴电机 反转1圈,30步为一圈 方向往左旋转
delay(1000);
for (pos = 180; pos >= 0; pos -= 1) //舵机顺时旋转 打开爪子
{ // 从 180 度旋转到 0 度,每次 1 度
myservo.write(pos); // 告诉 servo 走到 'pos' 的位置
delay(15); // 等待 15ms 让 servo 走到指定位置
}
delay(2000);
step(true, X_DIR, X_STP, 240); // X轴电机 正转1圈,200步为一圈 方向往後
delay(1000);
step(true, Y_DIR, Y_STP, 240); // y轴电机 正转1圈,200步为一圈 方向往下
delay(1000);
step(true, Z_DIR, Z_STP, 240); // z轴电机 正转1圈,200步为一圈 方向往右
delay(1000);
for (pos = 0; pos <= 180; pos += 1) // 舵机逆时转 180度爪子关
{ // 从 0 度旋转到 180 度,每次 1 度
myservo.write(pos); // 告诉 servo 走到 'pos' 的位置
delay(15); // 等待 15ms 让 servo 走到指定位置
}
delay(2000);
} sujieluck 发表于 2022-8-24 10:12
#include
#include
#include
感谢,之前遗漏了没有把代码发上:lol
页:
[1]