|
@@ -20,18 +20,22 @@ 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 ros_arduino_python.balance_mode import BalanceMode
|
|
|
|
|
|
|
|
|
""" Class to receive Twist commands and publish wheel Odometry data """
|
|
|
class BaseController:
|
|
|
- def __init__(self, is_use_serial, arduino, base_frame):
|
|
|
+ def __init__(self, is_use_serial, arduino, base_frame, cmd_topic, balance_mode):
|
|
|
self.use_serial = is_use_serial
|
|
|
self.arduino = arduino
|
|
|
self.base_frame = base_frame
|
|
|
+ self.isBalance = balance_mode
|
|
|
+ self.cmd_topic = cmd_topic
|
|
|
+ self.PID_rate = 100 #下位机中pid固定频率100hz
|
|
|
+
|
|
|
self.odom_name = rospy.get_param("~odom_name", "odom")
|
|
|
- self.cmd_topic = rospy.get_param("~cmd_topic", "cmd_vel")
|
|
|
self.debugPID = rospy.get_param('/dynamic_tutorials/debugPID', False)
|
|
|
-
|
|
|
+
|
|
|
pid_params = dict()
|
|
|
pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", 0.067)
|
|
|
pid_params['wheel_track'] = rospy.get_param("~wheel_track", 0.126)
|
|
@@ -51,8 +55,6 @@ class BaseController:
|
|
|
self.linear_scale_correction = rospy.get_param("~linear_scale_correction", 1.0)
|
|
|
self.angular_scale_correction = rospy.get_param("~angular_scale_correction", 1.0)
|
|
|
|
|
|
- #rospy.loginfo("pid_params_dict: "+pid_params)
|
|
|
-
|
|
|
# Set up PID parameters and check for missing values
|
|
|
self.setup_pid(pid_params)
|
|
|
|
|
@@ -66,7 +68,7 @@ class BaseController:
|
|
|
now = rospy.Time.now()
|
|
|
self.old_time = now # time for determining dx/dy
|
|
|
|
|
|
- #用于保存读取的左右电机的编码器计数值
|
|
|
+ #用于保存读取的电机编码器计数值
|
|
|
self.enc_A = 0
|
|
|
self.enc_B = 0
|
|
|
|
|
@@ -74,17 +76,21 @@ class BaseController:
|
|
|
self.y = 0 #在平面上Y轴方向位移
|
|
|
self.th = 0 #在平面上朝向
|
|
|
|
|
|
- self.v_A = 0
|
|
|
+ self.v_A = 0 #真正发送给下位机的脉冲数
|
|
|
self.v_B = 0
|
|
|
|
|
|
- self.v_des_AWheel = 0 # cmd_vel setpoint
|
|
|
+ self.v_des_AWheel = 0 #计算出来应该发送的脉冲数
|
|
|
self.v_des_BWheel = 0
|
|
|
|
|
|
self.last_cmd_time = now
|
|
|
|
|
|
- # Subscriptions main comtrol board to send control cmd
|
|
|
+ #设置订阅控制移动话题的回调函数
|
|
|
rospy.Subscriber(self.cmd_topic, Twist, self.cmdVelCallback)
|
|
|
|
|
|
+ #只有开启了平衡车模式才初始化平衡模式
|
|
|
+ if self.isBalance:
|
|
|
+ self.balanceControl = BalanceMode()
|
|
|
+
|
|
|
#初始化时,将电机编码器计数值清零
|
|
|
if self.use_serial:
|
|
|
self.arduino.reset_encoders()
|
|
@@ -104,7 +110,7 @@ class BaseController:
|
|
|
self.AVelPub = rospy.Publisher('Avel', Int32, queue_size=10)
|
|
|
self.BVelPub = rospy.Publisher('Bvel', Int32, queue_size=10)
|
|
|
|
|
|
- rospy.loginfo("Started base controller for a base of " + str(self.wheel_track) + "m with " + str(self.encoder_resolution) + " ticks per rev")
|
|
|
+ rospy.loginfo("Started base controller of " + str(self.wheel_track) + "m with " + str(self.encoder_resolution) + " ticks per rev")
|
|
|
|
|
|
def setup_pid(self, pid_params):
|
|
|
# Check to see if any PID parameters are missing
|
|
@@ -118,7 +124,7 @@ class BaseController:
|
|
|
os._exit(1)
|
|
|
|
|
|
self.encoder_resolution = pid_params['encoder_resolution']
|
|
|
- self.gear_reduction = pid_params['gear_reduction']
|
|
|
+ self.gear_reduction = pid_params['gear_reduction']
|
|
|
self.wheel_diameter = pid_params['wheel_diameter']
|
|
|
self.wheel_track = pid_params['wheel_track']
|
|
|
self.wheel_track = self.wheel_track/self.angular_scale_correction
|
|
@@ -140,11 +146,21 @@ class BaseController:
|
|
|
self.arduino.i2c_update_pid(self.AWheel_Kp, self.AWheel_Kd, self.AWheel_Ki, self.AWheel_Ko,
|
|
|
self.BWheel_Kp, self.BWheel_Kd, self.BWheel_Ki, self.BWheel_Ko,)
|
|
|
|
|
|
- #底盘运动控制的主循环,执行频率由arduino_node中的频率决定
|
|
|
+ #底盘运动控制的主循环,执行频率由arduino_node中的频率决定,默认50hz
|
|
|
def poll(self):
|
|
|
#发送调试pid参数的数据
|
|
|
self.send_debug_pid()
|
|
|
|
|
|
+ #是否开启平衡车模式,计算pid周期内的脉冲数
|
|
|
+ if self.isBalance:
|
|
|
+ self.balanceControl.keepBalance()
|
|
|
+ data = self.balanceControl.motorPulse
|
|
|
+
|
|
|
+ if self.use_serial:
|
|
|
+ self.arduino.drive(-data, data)
|
|
|
+ else:
|
|
|
+ self.arduino.i2c_drive(-data, data)
|
|
|
+
|
|
|
#读取编码器计数值,用于计算里程计信息
|
|
|
try:
|
|
|
if self.use_serial:
|
|
@@ -261,18 +277,19 @@ class BaseController:
|
|
|
self.AVelPub.publish(self.v_A)
|
|
|
self.BVelPub.publish(self.v_B)
|
|
|
|
|
|
+ #控制小车移动话题的回调函数,用于计算得到每个pid周期内电机转动的脉冲数
|
|
|
def cmdVelCallback(self, req):
|
|
|
self.last_cmd_time = rospy.Time.now()
|
|
|
|
|
|
- x = req.linear.x # x轴方向线速度 m/s
|
|
|
- th = req.angular.z # z轴转动角速度 rad/s
|
|
|
+ x = req.linear.x #x轴方向线速度m/s
|
|
|
+ th = req.angular.z #z轴转动角速度rad/s
|
|
|
|
|
|
- #两轮小车逆运动学模型,得到左右电机转速
|
|
|
+ #两轮小车逆运动学模型,计算得到左右电机转速
|
|
|
vA = -(x + 0.5*self.wheel_track*th)
|
|
|
vB = (x - 0.5*self.wheel_track*th)
|
|
|
|
|
|
- self.v_des_AWheel = int(vA * self.ticks_per_meter / self.arduino.PID_RATE)
|
|
|
- self.v_des_BWheel = int(vB * self.ticks_per_meter / self.arduino.PID_RATE)
|
|
|
+ self.v_des_AWheel = int(vA * self.ticks_per_meter / self.PID_rate)
|
|
|
+ self.v_des_BWheel = int(vB * self.ticks_per_meter / self.PID_rate)
|
|
|
#rospy.loginfo("cmdCallback(): A v_des:"+str(self.v_des_AWheel)+",B v_des:"+str(self.v_des_BWheel))
|
|
|
|
|
|
#用于调试电机PID参数
|