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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

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

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

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

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

十、ROS與arduino連接

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

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

本部分完成效果如下

1.虛擬機與arduino的連接

(1)arduino連接與IDE

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

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

(2)PCA9685模塊支持與測試


以上為原理圖,連接好線后我們要下載關于PCA9685模塊的支持庫進行測試。

在arudino IDE中打開庫管理,搜索Adafruit pwm Servo Driver Library,然后進行安裝


在該庫的示例下打開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
}

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

#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后,上載程序,極大可能報錯

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

說明沒有權限,更改權限就可以了

$ sudo chmod 777 /dev/ttyACM0 

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

若正確接線,效果如下,

2.ROS與arduino連接測試

(1)Arduino安裝rosserial

運行命令安裝rosserial_arduino包,

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

在庫管理中添加Rosserial Arduino庫

可以打開示例如下,

(2)rosserial測試

使用blink程序進行測試,打開示例程序,

#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后,打開一個終端運行命令,

$ roscore

接下來,運行rosserial客戶端應用程序,它將Arduino消息轉發給其他ROS。確保使用正確的串口:

rosrun rosserial_python serial_node.py /dev/ttyACM0

用rostopic切換LED:

rostopic pub toggle_led std_msgs/Empty --once

若運行正常,則每輸入一次命令,燈會進行一次操作。

3.ROS與arduino連接

在完成了所有準備工作之后我們就可以進行下一步了

(1)ros2ard節點

因為舵機的控制信息和我們計算使用的角度信息不相同,所以我們就需要一個轉換節點,接收節點信息,并進行轉換,發布給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)# 注意這里的各種參數是經過測試計算之后得出的,不具有普適性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)# 注意這里的各種參數是經過測試之后得出的,+600是因為我們使用的是UInt,為了確保角度不為負數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節點

為了給ros2ard節點發布角度信息,所以我們需要修改一下arm_command,使其發布節點信息

#!/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訂閱節點信息,并控制舵機移動,程序編寫如下,

#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)批處理

由于需要啟動的東西有點多了,所以一個比較好的方法使利用批處理命令,建立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"
}&

這樣我們比較方便的運行命令了

(5)程序運行

運行命令打開gazebo

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

新建終端,

./setup.sh

就可以像之前一樣運行程序了,打開rqt_graph 查看節點圖

效果如下,

十一、小結

不知為何,最近虛擬機非??D,以至于無法完成正常的圖像處理,不過所有預想的功能都已經實現了,所以這個arm0項目就算是完成了吧。畢竟初衷就是一個練手項目,有很多優化沒有時間去做。而且虛擬機還因為win10強制更新而導致的強制關閉出錯了,估計也需要重新安裝一遍系統。

接下來就是SLAM了,等后面學習完SLAM將其結合起來,這又是下一個項目了。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。