日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

【从零开始的ROS四轴机械臂控制】(七)- ROS与arduino连接

發(fā)布時(shí)間:2023/11/27 生活经验 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【从零开始的ROS四轴机械臂控制】(七)- ROS与arduino连接 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

從零開始的ROS四軸機(jī)械臂控制(七)

    • 十、ROS與arduino連接
      • 1.虛擬機(jī)與arduino的連接
        • (1)arduino連接與IDE
        • (2)PCA9685模塊支持與測(cè)試
      • 2.ROS與arduino連接測(cè)試
        • (1)Arduino安裝rosserial
        • (2)rosserial測(cè)試
      • 3.ROS與arduino連接
        • (1)ros2ard節(jié)點(diǎn)
        • (2)arm_command節(jié)點(diǎn)
        • (3)arduino訂閱
        • (4)批處理
        • (5)程序運(yùn)行
    • 十一、小結(jié)

十、ROS與arduino連接

回到許久沒有動(dòng)的硬件上來,考慮到我使用的是虛擬機(jī),所以首先要測(cè)試的是虛擬機(jī)與arduino的連接,然后才能考慮ROS與arduino的連接。

寫這部分的時(shí)候不知道為什么markdown編輯器“炸”掉了,編輯好的文本成了一堆亂碼,關(guān)鍵這堆亂碼還被保存了。由于之前沒有出現(xiàn)過這種情況,我習(xí)慣性的用編輯器做記錄,現(xiàn)在基本上都沒了。于是就導(dǎo)致了一個(gè)問題,我可能在重新編輯的時(shí)候忘記某些步驟,還是希望能注意一下。

本部分完成效果如下

1.虛擬機(jī)與arduino的連接

(1)arduino連接與IDE

首先將Arduino的連接到虛擬機(jī),只要在Vmware打開的情況下,它都會(huì)詢問是否連接到虛擬機(jī),或者直接在Player菜單–>可移動(dòng)設(shè)備中連接也可。

然后在虛擬機(jī)中安裝arduino IDE,在Linux安裝的具體方法可以百度或者Google上,在此不做詳細(xì)說明。安裝之后可以打開如下。

(2)PCA9685模塊支持與測(cè)試


以上為原理圖,連接好線后我們要下載關(guān)于PCA9685模塊的支持庫(kù)進(jìn)行測(cè)試。

在arudino IDE中打開庫(kù)管理,搜索Adafruit pwm Servo Driver Library,然后進(jìn)行安裝


在該庫(kù)的示例下打開servo示例如下,

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// you can also call it with a different address and I2C interface
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40, Wire);// Depending on your servo make, the pulse width min and max may vary, you 
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN  150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN  600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600
#define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates// our servo # counter
uint8_t servonum = 0;void setup() {Serial.begin(9600);Serial.println("8 channel Servo test!");pwm.begin();// In theory the internal oscillator is 25MHz but it really isn't// that precise. You can 'calibrate' by tweaking this number till// you get the frequency you're expecting!pwm.setOscillatorFrequency(27000000);  // The int.osc. is closer to 27MHz  pwm.setPWMFreq(SERVO_FREQ);  // Analog servos run at ~50 Hz updatesdelay(10);
}// You can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise!
void setServoPulse(uint8_t n, double pulse) {double pulselength;pulselength = 1000000;   // 1,000,000 us per secondpulselength /= SERVO_FREQ;   // Analog servos run at ~60 Hz updatesSerial.print(pulselength); Serial.println(" us per period"); pulselength /= 4096;  // 12 bits of resolutionSerial.print(pulselength); Serial.println(" us per bit"); pulse *= 1000000;  // convert input seconds to uspulse /= pulselength;Serial.println(pulse);pwm.setPWM(n, 0, pulse);
}void loop() {// Drive each servo one at a time using setPWM()Serial.println(servonum);for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {pwm.setPWM(servonum, 0, pulselen);}delay(500);for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {pwm.setPWM(servonum, 0, pulselen);}delay(500);// Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding!// The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) {pwm.writeMicroseconds(servonum, microsec);}delay(500);for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) {pwm.writeMicroseconds(servonum, microsec);}delay(500);servonum++;if (servonum > 7) servonum = 0; // Testing the first 8 servo channels
}

一個(gè)比較好的建議是,把以下部分的范圍改小,否則可能會(huì)損壞模型

#define SERVOMIN  150 // This is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  600 // This is the 'maximum' pulse length count (out of 4096)
#define USMIN  600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150
#define USMAX  2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600

使用IDE連接好arduino UNO后,上載程序,極大可能報(bào)錯(cuò)

[Errno 13] Permission denied: '/dev/ttyACM0'

說明沒有權(quán)限,更改權(quán)限就可以了

$ sudo chmod 777 /dev/ttyACM0 

程序順利上傳,不過這種方法只是臨時(shí)處理,在下次啟動(dòng)時(shí)需要重新輸入。

若正確接線,效果如下,

2.ROS與arduino連接測(cè)試

(1)Arduino安裝rosserial

運(yùn)行命令安裝rosserial_arduino包,

$ sudo apt-get install ros-indigo-rosserial-arduino
$ sudo apt-get install ros-indigo-rosserial

在庫(kù)管理中添加Rosserial Arduino庫(kù)

可以打開示例如下,

(2)rosserial測(cè)試

使用blink程序進(jìn)行測(cè)試,打開示例程序,

#include <ros.h>
#include <std_msgs/Empty.h>ros::NodeHandle nh;void messageCb( const std_msgs::Empty& toggle_msg){digitalWrite(13, HIGH-digitalRead(13));   // blink the led
}ros::Subscriber<std_msgs::Empty> sub("toggle_led", &messageCb );void setup()
{pinMode(13, OUTPUT);nh.initNode();nh.subscribe(sub);
}void loop()
{nh.spinOnce();delay(1);
}

將程序上載到arduino后,打開一個(gè)終端運(yùn)行命令,

$ roscore

接下來,運(yùn)行rosserial客戶端應(yīng)用程序,它將Arduino消息轉(zhuǎn)發(fā)給其他ROS。確保使用正確的串口:

rosrun rosserial_python serial_node.py /dev/ttyACM0

用rostopic切換LED:

rostopic pub toggle_led std_msgs/Empty --once

若運(yùn)行正常,則每輸入一次命令,燈會(huì)進(jìn)行一次操作。

3.ROS與arduino連接

在完成了所有準(zhǔn)備工作之后我們就可以進(jìn)行下一步了

(1)ros2ard節(jié)點(diǎn)

因?yàn)槎鏅C(jī)的控制信息和我們計(jì)算使用的角度信息不相同,所以我們就需要一個(gè)轉(zhuǎn)換節(jié)點(diǎn),接收節(jié)點(diǎn)信息,并進(jìn)行轉(zhuǎn)換,發(fā)布給arduino

#!/usr/bin/env pythonimport math
import rospy
from std_msgs.msg import UInt16MultiArray,  Float64MultiArray
from sensor_msgs.msg import JointState
from arm1.srv import *class ros2ard(object):def __init__(self):node_name = 'ros2ard'rospy.init_node(node_name)# init Publisherself.pub1 = rospy.Publisher('/ros2ard/joint_msg', UInt16MultiArray, queue_size=10)# init Subscriberrospy.Subscriber('/arm_command/joint_val', Float64MultiArray, self.callback)# 注意這里的各種參數(shù)是經(jīng)過測(cè)試計(jì)算之后得出的,不具有普適性def cal(self, angle):joint_value = int(1.89*91.80/1.57*angle) return joint_valuedef callback(self, joint_msg):print(joint_msg.data)# 注意這里的各種參數(shù)是經(jīng)過測(cè)試之后得出的,+600是因?yàn)槲覀兪褂玫氖荱Int,為了確保角度不為負(fù)數(shù)joint0_msg = self.cal(joint_msg.data[0])joint1_msg = 390 - self.cal(joint_msg.data[1])+ 600joint2_msg = 210 - self.cal(joint_msg.data[2])+ 600joint3_msg = 230 - self.cal(joint_msg.data[3])+ 600joint4_msg = 300+ 600joint_value = [joint0_msg, joint1_msg, joint2_msg, joint3_msg, joint4_msg]joint_message = UInt16MultiArray(data=joint_value)print('joint_msg', joint_message.data)self.pub1.publish(joint_message)if __name__ == '__main__':try:ros2ard()rospy.spin()except rospy.ROSInterruptException:pass

(2)arm_command節(jié)點(diǎn)

為了給ros2ard節(jié)點(diǎn)發(fā)布角度信息,所以我們需要修改一下arm_command,使其發(fā)布節(jié)點(diǎn)信息

#!/usr/bin/env pythonimport math
import rospy
from std_msgs.msg import Float64, Bool, Float64MultiArray
from sensor_msgs.msg import JointState
from arm1.srv import *class ArmCommand(object):def __init__(self):...self.pub3 = rospy.Publisher('/arm_command/joint_val', Float64MultiArray, queue_size=10)...# set all positions of joints with this functiondef arm_pos_set(self, joint1=0.0, joint2=0.52,joint3=-1.57,joint4=0.98,right_joint=1.0,left_joint=1.0,pos_init=False):self.msg.joint1 = joint1self.msg.joint2 = self.value_translation(joint2, 'joint2', 'cal2gaz')self.msg.joint3 = self.value_translation(joint3, 'joint3', 'cal2gaz')self.msg.joint4 = self.value_translation(joint4, 'joint4', 'cal2gaz')self.msg.right_joint = right_jointself.msg.left_joint = left_jointresponse = self.arm_mover(self.msg)joint_value = [joint1, joint2, joint3, joint4, right_joint]joint_msg = Float64MultiArray(data=joint_value)self.pub3.publish(joint_msg)if pos_init:rospy.loginfo('init all joints position')...
...

(3)arduino訂閱

我們需要使arduino訂閱節(jié)點(diǎn)信息,并控制舵機(jī)移動(dòng),程序編寫如下,

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include <WProgram.h>
#endif#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <ros.h>
#include <std_msgs/UInt16MultiArray.h>Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();#define SERVO_FREQ 50 ros::NodeHandle  nh;void servo_set(const std_msgs::UInt16MultiArray& cmd_msg) { pwm.setPWM(0, 0, cmd_msg.data[0]-600);pwm.setPWM(1, 0, cmd_msg.data[1]-600);pwm.setPWM(2, 0, cmd_msg.data[2]-600);pwm.setPWM(3, 0, cmd_msg.data[3]-600);pwm.setPWM(4, 0, cmd_msg.data[4]-600);digitalWrite(13, HIGH - digitalRead(13));
}ros::Subscriber<std_msgs::UInt16MultiArray> sub("/ros2ard/joint_msg", servo_set);void setup() {pinMode(13, OUTPUT);pwm.begin();pwm.setOscillatorFrequency(27000000);  pwm.setPWMFreq(SERVO_FREQ); pwm.setPWM(0, 0, 400);pwm.setPWM(1, 0, 270);pwm.setPWM(2, 0, 450);pwm.setPWM(3, 0, 130);pwm.setPWM(4, 0, 300);digitalWrite(13, HIGH - digitalRead(13));nh.initNode();nh.subscribe(sub);}void loop() {nh.spinOnce();delay(1000);
}

(4)批處理

由于需要啟動(dòng)的東西有點(diǎn)多了,所以一個(gè)比較好的方法使利用批處理命令,建立setup.sh文件,

#!/bin/bashsource ~/catkin_ws/devel/setup.bash{
gnome-terminal -t "img_process" -x bash -c "rosrun arm1 image_process;exec bash"
}&sleep 5s{
gnome-terminal -t "arm_command" -x bash -c "rosrun arm1 arm_command;exec bash"
}&sleep 5s{
gnome-terminal -t "ros2ard" -x bash -c "rosrun arm1 ros2ard;exec bash"
}&sleep 5s
{
gnome-terminal -t "ros2ard" -x bash -c "rosrun rosserial_python serial_node.py /dev/ttyACM0;exec bash"
}&

這樣我們比較方便的運(yùn)行命令了

(5)程序運(yùn)行

運(yùn)行命令打開gazebo

$ source ~/catkin_ws/devel/setup.bash
$ roslaunch arm1 gazebo.launch

新建終端,

./setup.sh

就可以像之前一樣運(yùn)行程序了,打開rqt_graph 查看節(jié)點(diǎn)圖

效果如下,

十一、小結(jié)

不知為何,最近虛擬機(jī)非常卡頓,以至于無(wú)法完成正常的圖像處理,不過所有預(yù)想的功能都已經(jīng)實(shí)現(xiàn)了,所以這個(gè)arm0項(xiàng)目就算是完成了吧。畢竟初衷就是一個(gè)練手項(xiàng)目,有很多優(yōu)化沒有時(shí)間去做。而且虛擬機(jī)還因?yàn)閣in10強(qiáng)制更新而導(dǎo)致的強(qiáng)制關(guān)閉出錯(cuò)了,估計(jì)也需要重新安裝一遍系統(tǒng)。

接下來就是SLAM了,等后面學(xué)習(xí)完SLAM將其結(jié)合起來,這又是下一個(gè)項(xiàng)目了。

總結(jié)

以上是生活随笔為你收集整理的【从零开始的ROS四轴机械臂控制】(七)- ROS与arduino连接的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。