class RosCar(): def __init__(self, cfg): self.STEERING_NEUTRAL = cfg['servo_neutral_angle'] self.MIN_STEERING_ANGLE = cfg[ 'servo_min_angle_limit'] # Steering left/right max angle. self.MAX_STEERING_ANGLE = cfg[ 'servo_max_angle_limit'] # Steering left/right max angle. self.STEERING_RATE = cfg[ 'steering_rate'] # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle. self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed'] self.MOTOR_FORWARD_SPEED_RATE = float( cfg['motor_max_speed_limit'] ) / float( 100 ) # Server max speed is 100. But car_client depends on config parameter. self.MOTOR_BACK_SPEED_RATE = float( cfg['motor_min_speed_limit'] ) / float( -100 ) # Server min speed is -100. But car_client depends on config parameter. self.steering = Servo(cfg) self.motor = Motor(cfg) self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) self.speed = self.MOTOR_NEUTRAL_SPEED self.back_in = False self.back_start_time = None return def __del__(self): self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) return def listener(self): """ READ ROS TOPICS AND RUN FUNCTION BY HZ. rosnode list rosnode info /twist_filter rostopic echo /cmd_vel """ rospy.init_node('ROSCarNano', anonymous=True) rospy.Subscriber('/cmd_vel', Twist, self.cmd_vel) # spin() simply keeps python from exiting until this node is stopped rospy.spin() return def cmd_vel(self, values): """ ステアリング・速度のターゲット値の処理 ステアリング値のomegaはターゲット角速度である。現在の速度を加味してomegaを算出しなければならない self.target_speed: target speed (m/s) """ """ Autoware 1.9.1にバック機能は無い。 そのため速度は負の値は正の値として扱う。 """ print("/cmd_vel: {}".format(values)) speed = abs(values.linear.x) target_speed = map(speed, 0.0, 0.22, 0.0, 30.0) """ Autowareの角速度は右カーブがマイナス、左カーブがプラス。 omega: rad/s and 10 Hz 1 processing = 1 Hz = 0.1 * omega left/right = -1 * omega """ omega = values.angular.z """ omegaはtarget_speedが時速2kmの時、ベストマッチ。 速度が上がった時、それに応じてomegaを減算させる。 """ print("omega: {} speed: {}".format(omega, speed)) self.set_speed(target_speed) self.set_angle_rad(omega) return def omega_to_angle(self, omega): """ 角速度ωをサーボ可動域に変換する。 omegaは右カーブがマイナス、左カーブがプラス。 サーボは右カーブが90-180度、左カーブが0-90度となるため、 omegaの正負を逆にしてdegreeに変換してから90度加える。 ω(rad/s) θ= ω*180/pi (deg/s) rad = θ*pi/180 """ omega = -1.0 * omega theta = float(omega) * float(180) / math.pi angle = 90.0 - (180.0 - theta) / 2.0 return angle def set_angle_rad(self, omega): """ omega: rad/s """ steering_angle = self.omega_to_angle(omega) #print("omega to angle: {} -> {}".format(omega, steering_angle)) steering_angle = int(float(steering_angle) * float(self.STEERING_RATE)) steering_angle = self.STEERING_NEUTRAL + steering_angle """ Adjust within operable angle """ if steering_angle > self.MAX_STEERING_ANGLE: steering_angle = self.MAX_STEERING_ANGLE if steering_angle < self.MIN_STEERING_ANGLE: steering_angle = self.MIN_STEERING_ANGLE print("steering: {}".format(steering_angle)) self.steering.set_angle(steering_angle) def set_speed(self, speed): """ speed: Analog int value for PCA9685 """ motor_speed = speed if motor_speed > 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE)) elif motor_speed < 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE)) self.motor.set_speed(motor_speed) def brake(self, value): if value.data: self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
def main(): print("start") motor = None try: """ LOAD SETUP VARIABLES """ cfg = load_config() motor = Motor(cfg) """ # NEUTRAL ANALOG RANGE: 370-393 neutral = 370 print(motor.analog_to_pulse(neutral)) neutral = 393 print(motor.analog_to_pulse(neutral)) # FORWARD MAXIMUM ANALOG VALUE: 280 analog = 280 print(motor.analog_to_pulse(analog)) # BACKWARD MAXIMUM ANALOG VALUE: 440 analog = 440 print(motor.analog_to_pulse(analog)) """ # FORWARD: 369(START) - 280(MAX SPEED) motor.set_speed(0) time.sleep(2) speed = 0 """ for i in range(100): speed += 1 motor.set_speed(speed) print(motor.get_speed()) time.sleep(0.1) for i in range(100): speed -= 1 motor.set_speed(speed) print(motor.get_speed()) time.sleep(0.1) """ # Setting the "BACKWARD" value to the value will apply the brake. (It is probably the function of ESC.) # BACKWORD: 394(START) - 440(MAX SPEED) speed = -30 # 30% backword throttle delay = 5.0 for i in range(2): speed = 30 # 30% throttle motor.set_speed(speed, delay) time.sleep(2.5) speed = 0 motor.set_speed(speed, delay) time.sleep(2.5) motor.set_speed(0) time.sleep(2) except: import traceback traceback.print_exc() finally: if motor is not None: motor.set_speed(0) time.sleep(3) print("end")
class RosCar(): def __init__(self, cfg): self.STEERING_NEUTRAL = cfg['servo_neutral_angle'] self.MIN_STEERING_ANGLE = cfg[ 'servo_min_angle_limit'] # Steering left/right max angle. self.MAX_STEERING_ANGLE = cfg[ 'servo_max_angle_limit'] # Steering left/right max angle. self.STEERING_RATE = cfg[ 'steering_rate'] # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle. self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed'] self.MOTOR_FORWARD_SPEED_RATE = float( cfg['motor_max_speed_limit'] ) / float( 100 ) # Server max speed is 100. But car_client depends on config parameter. self.MOTOR_BACK_SPEED_RATE = float( cfg['motor_min_speed_limit'] ) / float( -100 ) # Server min speed is -100. But car_client depends on config parameter. self.steering = Servo(cfg) self.motor = Motor(cfg) self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) self.speed = self.MOTOR_NEUTRAL_SPEED return def __del__(self): self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) return def listener(self): """ ROS Topicの更新時に処理を行う設定 rosnode list rostopic echo /cmd_vel rostopic echo /ackermann_cmd """ rospy.init_node('ROSCarNano', anonymous=True) """ アッカーマン運動力学 """ ackermann = AckermannPublisher() ackermann.add() rospy.Subscriber('/ackermann_cmd', AckermannDriveStamped, self.ackermann_cmd) # spin() simply keeps python from exiting until this node is stopped rospy.spin() return def ackermann_cmd(self, values): """ ステアリング・速度のターゲット値の処理 ステアリング値のsteering_angleは角度(rad)なので、degreeに変換する speed: m/s target_speed: motor power % # map(指示を受けた速度(m/s), 指示速度の後方最高速度m/s, 指示速度の最高速度m/s, モーター後方最高出力%, モーター前方最高出力%) # ここでは前後モーター最高出力は100%として、デバイス設定時に車両設定の速度制限を適用する。 """ print("/ackermann_cmd: {}".format(values)) #speed = abs(values.drive.speed) # no backwords speed = values.drive.speed target_speed = map(speed, -0.28, 0.28, -100.0, 100.0) """ ステアリング角 アッカーマン運動力学のステアリング角を利用する """ angle_rad = values.drive.steering_angle self.set_speed(target_speed) self.set_angle_rad(angle_rad) def rad_to_angle(self, angle_rad): """ angle_radをサーボ可動域に変換する。 angle_radは右カーブがマイナス、左カーブがプラス。 サーボは右カーブが90-180度、左カーブが0-90度となるため、 angle_radの正負を逆にしてdegreeに変換してから90度加える。 ω(rad/s) θ= angle_rad*180/pi (deg/s) rad = θ*pi/180 """ angle_rad = -1.0 * angle_rad theta = float(angle_rad) * float(180) / math.pi angle = 90.0 - (180.0 - theta) / 2.0 return angle def set_angle_rad(self, angle_rad): """ omega: rad/s """ steering_angle = self.rad_to_angle(angle_rad) #print("omega to angle: {} -> {}".format(omega, steering_angle)) steering_angle = int(float(steering_angle) * float(self.STEERING_RATE)) steering_angle = self.STEERING_NEUTRAL + steering_angle """ Adjust within operable angle """ if steering_angle > self.MAX_STEERING_ANGLE: steering_angle = self.MAX_STEERING_ANGLE if steering_angle < self.MIN_STEERING_ANGLE: steering_angle = self.MIN_STEERING_ANGLE print("steering: {}".format(steering_angle)) self.steering.set_angle(steering_angle) def set_speed(self, speed): """ speed: Analog int value for PCA9685 """ motor_speed = speed if motor_speed > 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE)) elif motor_speed < 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE)) print("motor: {}".format(motor_speed)) self.motor.set_speed(motor_speed) def brake(self, value): if value.data: self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
class RosCar(): def __init__(self, cfg): self.STEERING_NEUTRAL = cfg['servo_neutral_angle'] self.MIN_STEERING_ANGLE = cfg[ 'servo_min_angle_limit'] # Steering left/right max angle. self.MAX_STEERING_ANGLE = cfg[ 'servo_max_angle_limit'] # Steering left/right max angle. self.STEERING_RATE = cfg[ 'steering_rate'] # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle. self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed'] self.MOTOR_FORWARD_SPEED_RATE = float( cfg['motor_max_speed_limit'] ) / float( 100 ) # Server max speed is 100. But car_client depends on config parameter. self.MOTOR_BACK_SPEED_RATE = float( cfg['motor_min_speed_limit'] ) / float( -100 ) # Server min speed is -100. But car_client depends on config parameter. self.steering = Servo(cfg) self.motor = Motor(cfg) self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) return def listener(self): """ READ ROS TOPICS AND RUN FUNCTION BY HZ. angle_deg: -45 to 45 speed_deg: -100 to 100 brake_bool: True or False """ rospy.init_node('RoboCarROS', anonymous=True) rospy.Subscriber('/steer/angle_deg', Int8, self.set_angle) rospy.Subscriber('/motor/speed_deg', Int8, self.set_speed) rospy.Subscriber('/motor/brake_bool', Bool, self.brake) # spin() simply keeps python from exiting until this node is stopped rospy.spin() return def set_angle(self, angle): """ angle.data: -45 to 45 degree. """ steering_angle = angle.data steering_angle = int(float(steering_angle) * float(self.STEERING_RATE)) steering_angle = self.STEERING_NEUTRAL + steering_angle """ Adjust within operable angle """ if steering_angle > self.MAX_STEERING_ANGLE: steering_angle = self.MAX_STEERING_ANGLE if steering_angle < self.MIN_STEERING_ANGLE: steering_angle = self.MIN_STEERING_ANGLE self.steering.set_angle(steering_angle) def set_speed(self, speed): motor_speed = speed.data if motor_speed > 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE)) elif motor_speed < 0: motor_speed = int( float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE)) self.motor.set_speed(motor_speed) def brake(self, value): if value.data: self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)
class RosCar(): def __init__(self, cfg): self.STEERING_NEUTRAL = cfg['servo_neutral_angle'] self.MIN_STEERING_ANGLE = cfg['servo_min_angle_limit'] # Steering left/right max angle. self.MAX_STEERING_ANGLE = cfg['servo_max_angle_limit'] # Steering left/right max angle. self.STEERING_RATE = cfg['steering_rate'] # Server steering angle is fomula angle. But car_client depends on car. Drift type steering, normal steering, etc. Therefore, use this rate for ajust good angle. self.MOTOR_NEUTRAL_SPEED = cfg['motor_neutral_speed'] self.MOTOR_FORWARD_SPEED_RATE = float(cfg['motor_max_speed_limit'])/float(100) # Server max speed is 100. But car_client depends on config parameter. self.MOTOR_BACK_SPEED_RATE = float(cfg['motor_min_speed_limit'])/float(-100) # Server min speed is -100. But car_client depends on config parameter. self.steering = Servo(cfg) self.motor = Motor(cfg) self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) self.speed = self.MOTOR_NEUTRAL_SPEED self.back_in = False self.back_start_time = None self.target_speed = self.MOTOR_NEUTRAL_SPEED return def __del__(self): self.steering.set_angle(self.STEERING_NEUTRAL, delay=0) self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0) return def listener(self): """ READ ROS TOPICS AND RUN FUNCTION BY HZ. rosnode list rosnode info /twist_filter rostopic echo /twist_cmd """ rospy.init_node('RoboCarROS', anonymous=True) rospy.Subscriber('/twist_cmd', TwistStamped, self.twist_cmd) # current_velocity rospy.Subscriber('/current_velocity', TwistStamped, self.current_velocity) # spin() simply keeps python from exiting until this node is stopped rospy.spin() return def current_velocity(self, values): """ 現在速度と目標速度を比較して、モーター出力を調整する。 self.speed: モーター出力 current_velocity: 現在速度 self.target_speed: 目標速度 """ current_velocity = values.twist.linear.x print("speed now: {} target: {}".format(current_velocity, self.target_speed)) if current_velocity < self.target_speed: self.speed += 1 elif current_velocity > self.target_speed: self.speed -= 1 if self.speed >= 100: self.speed = 100 elif self.speed <= 0: self.speed = 0 """ 現在速度が0.1(m/s)未満の時、急発進を抑えるためにモーター出力を制限する。 """ if self.speed > 25 and current_velocity < 0.1: self.speed = 25 self.set_speed(self.speed) return def twist_cmd(self, values): """ ステアリング・速度のターゲット値の処理 ステアリング値はここで適用する 速度は変数で保持し、current_velocityによる現在速度取得時に適用する ステアリング値のomegaはターゲット角速度である。現在の速度を加味してomegaを算出しなければならない self.target_speed: target speed (m/s) """ #print(values) """ Autoware 1.9.1にバック機能は無い。 そのため速度は負の値は正の値として扱う。 """ speed = abs(values.twist.linear.x) self.target_speed = speed """ Autowareの角速度は右カーブがマイナス、左カーブがプラス。 omega: rad/s and 10 Hz 1 processing = 1 Hz = 0.1 * omega left/right = -1 * omega """ omega = values.twist.angular.z """ omegaはtarget_speedが時速2kmの時、ベストマッチ。 速度が上がった時、それに応じてomegaを減算させる。 """ print("before omega: {} speed: {}".format(omega, speed)) if self.target_speed >= 0.56: """ 目標速度が時速2km(0.56m/s)以上の時、比率に応じてomegaを小さくする """ ratio = map(self.target_speed, 2.0, 1000.0, 1.0, 1000.0) omega = omega*ratio print("after omega: {} speed: {}".format(omega, speed)) self.set_angle_rad(omega) return def omega_to_angle(self, omega): """ 角速度ωをサーボ可動域に変換する。 omegaは右カーブがマイナス、左カーブがプラス。 サーボは右カーブが90-180度、左カーブが0-90度となるため、 omegaの正負を逆にしてdegreeに変換してから90度加える。 ω(rad/s) θ= ω*180/pi (deg/s) rad = θ*pi/180 """ omega = -1.0 * omega theta = float(omega)*float(180)/math.pi angle = 90.0 - (180.0 - theta)/2.0 return angle def set_angle_rad(self, omega): """ omega: rad/s """ steering_angle = self.omega_to_angle(omega) #print("omega to angle: {} -> {}".format(omega, steering_angle)) steering_angle = int(float(steering_angle) * float(self.STEERING_RATE)) steering_angle = self.STEERING_NEUTRAL + steering_angle """ Adjust within operable angle """ if steering_angle > self.MAX_STEERING_ANGLE: steering_angle = self.MAX_STEERING_ANGLE if steering_angle < self.MIN_STEERING_ANGLE: steering_angle = self.MIN_STEERING_ANGLE print("steering: {}".format(steering_angle)) self.steering.set_angle(steering_angle) def set_speed(self, speed): """ speed: Analog int value for PCA9685 """ motor_speed = speed if motor_speed > 0: motor_speed = int(float(motor_speed) * float(self.MOTOR_FORWARD_SPEED_RATE)) elif motor_speed < 0: motor_speed = int(float(motor_speed) * float(self.MOTOR_BACK_SPEED_RATE)) self.motor.set_speed(motor_speed) def brake(self, value): if value.data: self.motor.set_speed(self.MOTOR_NEUTRAL_SPEED, delay=0)