Browse Source

新增imu发布y位移;更新里程计计算角度;新增pid控制直线;修复i2c读取pid值;修复i2c控制夹爪

zhuo 4 years ago
parent
commit
039471dfd3

+ 1 - 0
src/rasp_imu_hat_6dof/rasp_imu_hat_6dof/CMakeLists.txt

@@ -10,6 +10,7 @@ find_package(catkin REQUIRED COMPONENTS
 add_service_files(
     FILES
     GetYawData.srv
+    GetYpositionData.srv
 )
 
 generate_messages(

+ 1 - 0
src/rasp_imu_hat_6dof/rasp_imu_hat_6dof/cfg/param.yaml

@@ -11,5 +11,6 @@
 pub_data_topic: imu_data
 pub_temp_topic: imu_temp
 yaw_topic: yaw_data
+pub_yposition_topic: yposition_data
 link_name: base_imu_link
 pub_hz: 20

+ 32 - 1
src/rasp_imu_hat_6dof/rasp_imu_hat_6dof/nodes/imu_node.py

@@ -17,7 +17,7 @@
 import rospy
 import math
 
-from rasp_imu_hat_6dof.srv import GetYawData,GetYawDataResponse
+from rasp_imu_hat_6dof.srv import GetYawData,GetYawDataResponse,GetYpositionData,GetYpositionDataResponse
 from tf.transformations import quaternion_from_euler
 from dynamic_reconfigure.server import Server
 from rasp_imu_hat_6dof.cfg import imuConfig
@@ -30,10 +30,21 @@ degrees2rad = math.pi/180.0
 imu_yaw_calibration = 0.0
 yaw = 0.0
 
+y_position = 0
+y1_velocity = 0
+y2_velocity = 0
+y_acceleration = 0
+y_const_acceleration = 0
+y1_update_flag = 0
+
 # ros server return Yaw data
 def return_yaw_data(req):
     return GetYawDataResponse(yaw)
 
+# Ros server return Yposition data
+def return_yposition_data(req):
+    return GetYpositionDataResponse(y_position)
+
 # Callback for dynamic reconfigure requests
 def reconfig_callback(config, level):
     global imu_yaw_calibration
@@ -46,15 +57,20 @@ rospy.init_node("imu_node")
 # Get DIY config param
 data_topic_name = rospy.get_param('~pub_data_topic', 'imu_data')
 temp_topic_name = rospy.get_param('~pub_temp_topic', 'imu_temp')
+yposition_topic_name = rospy.get_param("~pub_yposition_topic","yposition_data")
 link_name  = rospy.get_param('~link_name', 'base_imu_link')
 pub_hz = rospy.get_param('~pub_hz', '20')
 yaw_topic_name = rospy.get_param('~yaw_topic', 'yaw_topic')
 
+delta_time = 0.05
+
 data_pub = rospy.Publisher(data_topic_name, Imu, queue_size=1)
 temp_pub = rospy.Publisher(temp_topic_name, Float32, queue_size=1)
 yaw_pub = rospy.Publisher(yaw_topic_name, Float32, queue_size=1)
+yposition_pub = rospy.Publisher(yposition_topic_name, Float32, queue_size=1)
 srv = Server(imuConfig, reconfig_callback)  # define dynamic_reconfigure callback
 yaw_srv = rospy.Service('imu_node/GetYawData', GetYawData, return_yaw_data)
+yposition_srv = rospy.Service('imu_node/GetYpositionData', GetYpositionData, return_yposition_data)
 
 imuMsg = Imu()
 yawMsg = Float32()
@@ -89,6 +105,11 @@ rate = rospy.Rate(pub_hz)
 
 rospy.loginfo("IMU Module is working ...")
 while not rospy.is_shutdown():
+
+    #Calculate y_position and Publish
+    y_position = y_position + y1_velocity * delta_time + 0.5 * y_acceleration * delta_time * delta_time
+    yposition_pub.publish(y_position)
+
     myIMU.get_YPRAG()
 
     #rospy.loginfo("yaw:%f pitch:%f  roll:%f", myIMU.raw_yaw,
@@ -141,5 +162,15 @@ while not rospy.is_shutdown():
     myIMU.get_temp()
     temp_pub.publish(myIMU.temp)
 
+    # Update y_velocity and y_accelerate
+    if y1_update_flag != 0:
+        y1_velocity = y2_velocity
+    else:
+        y_const_acceleration = imuMsg.linear_acceleration.y
+        y1_update_flag += 1
+    y_acceleration = imuMsg.linear_acceleration.y - y_const_acceleration
+    y2_velocity = y2_velocity + y_acceleration * delta_time
+    
+
     rate.sleep()
 

+ 2 - 0
src/rasp_imu_hat_6dof/rasp_imu_hat_6dof/srv/GetYpositionData.srv

@@ -0,0 +1,2 @@
+---
+float32 yposition

+ 13 - 0
src/ros_arduino_bridge/ros_arduino_python/config/my_arduino_params.yaml

@@ -66,3 +66,16 @@ sensors: {
   batPercent: {pin: 0, type: BAT_PERCENT, rate: 0.1, direction: input},
 }
 
+# Yaw Service
+yaw_data_service: imu_node/GetYawData
+
+# Yaw Target and PID
+yaw_target: 0
+yaw_kp: 2.5
+yaw_ki: 0.2
+yaw_kd: 0.11
+
+# Forward Yaw Error and Rate
+correction_forward_err_yaw_data: 0.00
+correction_forward_rate: 1
+

+ 13 - 16
src/ros_arduino_bridge/ros_arduino_python/src/ros_arduino_python/arduino_driver.py

@@ -387,7 +387,7 @@ class Arduino:
         else:
             '''control gripper open/close by IIC
             '''
-            cmd = (' %d %d\r' %(servoID, angle, delay))
+            cmd = (' %d %d %d\r' %(servoID, angle, delay))
             try:
                 self.i2c_bus.write_i2c_block_data(self.i2c_slave_addr, ord('s'), [ord(c) for c in cmd])
             except:
@@ -548,24 +548,25 @@ class Arduino:
             return values
 
     def i2c_get_pidin(self):
-        rospy.loginfo("IIC Get Pidin !")
-        ch = ''
-        values = ''
-        cnt = 0
-        cmd = "\r"
+        # rospy.loginfo("IIC Get Pidin !")
 
         try:
             self.i2c_bus.write_byte(self.i2c_slave_addr, int(ord('i')))
             self.i2c_bus.write_byte(self.i2c_slave_addr, ord('\r'))
 
             result_array3 = self.i2c_bus.read_i2c_block_data(self.i2c_slave_addr, 0x08)
-            print result_array
+            #print(result_array3)
             #There are result_flag valid bytes.
-            result_flag3 = result_array.index(120)
+            result_flag3 = result_array3.index(120)
             #print result_flag3
             #rospy.loginfo("Valid bytes: "+str(result_flag))
             #extract result_flag bytes as strings
-            result_string3=''.join([chr(ch) for ch in result_array3[0:(result_flag3-1)]])
+            if result_flag3 == 0:
+                result_array3 = result_array3[1:(len(result_array3)-1)]
+                result_flag3 = result_array3.index(120)
+                result_string3=''.join([chr(ch) for ch in result_array3[0:(result_flag3-1)]])
+            else:
+                result_string3=''.join([chr(ch) for ch in result_array3[0:(result_flag3-1)]])
             #print result_string3
             #extract Pidin_counts by space
             values=[int(s) for s in result_string3.split(" ")]
@@ -590,20 +591,16 @@ class Arduino:
             return values
 
     def i2c_get_pidout(self):
-        rospy.loginfo("IIC Get Pidout !")
-        ch = ''
-        values = ''
-        cnt = 0
-        cmd = "\r"
+        # rospy.loginfo("IIC Get Pidout !")
 
         try:
             self.i2c_bus.write_byte(self.i2c_slave_addr, int(ord('o')))
             self.i2c_bus.write_byte(self.i2c_slave_addr, ord('\r'))
 
             result_array4 = self.i2c_bus.read_i2c_block_data(self.i2c_slave_addr, 0x08)
-            print result_array
+            # print(result_array4)
             #There are result_flag valid bytes.
-            result_flag4 = result_array.index(120)
+            result_flag4 = result_array4.index(120)
             #print result_flag4
             #rospy.loginfo("Valid bytes: "+str(result_flag))
             #extract result_flag bytes as strings

+ 106 - 1
src/ros_arduino_bridge/ros_arduino_python/src/ros_arduino_python/base_controller.py

@@ -11,15 +11,79 @@
 """
 import os
 import rospy
+import time
 import roslib; roslib.load_manifest('ros_arduino_python')
 import dynamic_reconfigure.client
+import queue
 
 from math import sin, cos, pi, sqrt
+import numpy as np
 from geometry_msgs.msg import Quaternion, Twist
 from nav_msgs.msg import Odometry
 from tf.broadcaster import TransformBroadcaster
 from std_msgs.msg import Int32
-
+from rasp_imu_hat_6dof.srv import GetYawData
+
+class SimplePID:
+	'''very simple discrete PID controller'''
+	def __init__(self, target, P, I, D):
+		'''Create a discrete PID controller
+		each of the parameters may be a vector if they have the same length
+		
+		Args:
+		target (double) -- the target value(s)
+		P, I, D (double)-- the PID parameter
+
+		'''
+
+		# check if parameter shapes are compatabile. 
+		self.Kp		=np.array(P)
+		self.Ki		=np.array(I)
+		self.Kd		=np.array(D)
+		self.setPoint   =np.array(target)
+		
+		self.last_error=0
+		self.integrator = 0
+		self.integrator_max = float('inf')
+		self.timeOfLastCall = None 
+		
+		
+	def update(self, current_value):
+		'''Updates the PID controller. 
+
+		Args:
+			current_value (double): vector/number of same legth as the target given in the constructor
+
+		Returns:
+			controll signal (double): vector of same length as the target
+
+		'''
+		current_value=np.array(current_value)
+		if(self.timeOfLastCall is None):
+			# the PID was called for the first time. we don't know the deltaT yet
+			# no controll signal is applied
+			self.timeOfLastCall = time.clock()
+			return np.zeros(np.size(current_value))
+
+		
+		error = self.setPoint - current_value
+		P =  error
+		
+		currentTime = time.clock()
+		deltaT      = (currentTime-self.timeOfLastCall)
+
+		# integral of the error is current error * time since last update
+		self.integrator = self.integrator + (error*deltaT)
+		I = self.integrator
+		
+		# derivative is difference in error / time since last update
+		D = (error-self.last_error)/deltaT
+		
+		self.last_error = error
+		self.timeOfLastCall = currentTime
+		
+		# return controll signal
+		return self.Kp*P + self.Ki*I + self.Kd*D
 
 """ Class to receive Twist commands and publish wheel Odometry data """
 class BaseController:
@@ -34,6 +98,19 @@ class BaseController:
         self.rate       = float(rospy.get_param("~base_controller_rate", 20))
         self.timeout    = rospy.get_param("~base_controller_timeout", 0.7)
 
+        self.yaw_data_service = rospy.get_param("~yaw_data_service","imu_node/GetYawData")
+        self.yaw_target = rospy.get_param("~yaw_target",0)
+        self.yaw_kp = rospy.get_param("~yaw_kp",1)
+        self.yaw_ki = rospy.get_param("~yaw_ki",1)
+        self.yaw_kd = rospy.get_param("~yaw_kd",1)
+        self.correction_forward_err_yaw_data = rospy.get_param("~correction_forward_err_yaw_data",0.017)
+        self.correction_forward_rate = rospy.get_param("~correction_forward_rate",1)
+        self.pid_controller = SimplePID(self.yaw_target, self.yaw_kp, self.yaw_ki, self.yaw_kd)
+        self.correction_yaw_flag = 0
+        self.last_yaw_data = 0
+        self.now_yaw_data = 0
+        self.initial_odom_yaw_data = self.get_yaw()
+
         self.debugPID   = rospy.get_param('~debugPID', False)
 
         pid_params = dict()
@@ -243,6 +320,9 @@ class BaseController:
             self.pose_y += delta_y
             self.th += delta_th
 
+            self.now_odom_yaw_data = self.get_yaw()
+            self.th = self.now_odom_yaw_data - self.initial_odom_yaw_data
+
             quaternion   = Quaternion()
             quaternion.x = 0.0
             quaternion.y = 0.0
@@ -289,6 +369,7 @@ class BaseController:
             # send motor cmd
             if time_now > (self.last_cmd_time + rospy.Duration(self.timeout)):
                 self.stop()
+                self.correction_yaw_flag = 0
             else:
                 self.send_motor_speed()
 
@@ -373,8 +454,17 @@ class BaseController:
         self.v_des_BWheel = 0
         self.v_des_CWheel = 0
 
+    def get_yaw(self):
+        rospy.wait_for_service(self.yaw_data_service)
+        try: 
+            yaw_data = rospy.ServiceProxy(self.yaw_data_service, GetYawData)
+            resp = yaw_data()
+            return resp.yaw    
+        except rospy.ServiceException, e:            
+            print "Service call failed: %s"%e
 
     def cmdVelCallback(self, req):
+        
         # Handle velocity-based movement requests
         self.last_cmd_time = rospy.Time.now()
 
@@ -382,6 +472,21 @@ class BaseController:
         y  = req.linear.y  # m/s
         th = req.angular.z # rad/s
 
+        if x != 0 and y == 0 and th == 0:
+            if self.correction_yaw_flag < 2:
+                self.stop()
+                self.last_yaw_data = self.get_yaw()
+                self.correction_yaw_flag += 1
+                return
+            else:
+                self.now_yaw_data = self.get_yaw()
+                err_yaw_data = self.now_yaw_data - self.last_yaw_data
+                if abs(err_yaw_data) > self.correction_forward_err_yaw_data:
+                    th = self.pid_controller.update(err_yaw_data)
+                    print("err_yaw_data is ",err_yaw_data,"th is ",th)
+        else:
+            self.correction_yaw_flag = 0  
+
         #Inverse Kinematic
         tmpX = sqrt(3)/2.0
         tmpY = 0.5  # 1/2