line_follow.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import rospy
  4. import cv2
  5. import numpy as np
  6. from sensor_msgs.msg import Image
  7. from geometry_msgs.msg import Twist
  8. from cv_bridge import CvBridge
  9. class LineFollower:
  10. def __init__(self):
  11. rospy.init_node('line_follower')
  12. self.bridge = CvBridge()
  13. self.cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
  14. self.image_sub = rospy.Subscriber('/usb_cam/image_raw', Image, self.image_cb)
  15. # IPM 变换矩阵(需根据标定与安装角度实测填写)
  16. self.M = cv2.getPerspectiveTransform(self.src_pts, self.dst_pts)
  17. # PID 参数
  18. self.kp = 0.005; self.ki = 0.0; self.kd = 0.002
  19. self.last_err = 0.0
  20. rospy.spin()
  21. def image_cb(self, msg):
  22. frame = self.bridge.imgmsg_to_cv2(msg, 'bgr8')
  23. # 1. 逆透视变换
  24. bird = cv2.warpPerspective(frame, self.M, (frame.shape[1], frame.shape[0]))
  25. # 2. HSV 白线提取
  26. hsv = cv2.cvtColor(bird, cv2.COLOR_BGR2HSV)
  27. mask = cv2.inRange(hsv, (0,0,180), (180,60,255))
  28. # 3. 形态学去噪
  29. mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((5,5),np.uint8))
  30. # 4. 列投影直方图找右路中线
  31. col_sum = np.sum(mask[mask.shape[0]//2:,:], axis=0)
  32. # 取最右侧峰作为跟踪目标
  33. right_peak = self.find_rightmost_peak(col_sum)
  34. # 5. 计算偏移量并 PID
  35. err = right_peak - bird.shape[1]/2
  36. angular_z = -(self.kp*err + self.kd*(err-self.last_err))
  37. self.last_err = err
  38. # 6. 发布速度
  39. twist = Twist()
  40. twist.linear.x = 0.15
  41. twist.angular.z = np.clip(angular_z, -0.6, 0.6)
  42. self.cmd_pub.publish(twist)
  43. if __name__ == '__main__':
  44. LineFollower()