0
$\begingroup$

Rosanswers logo

I started to practice with python, and I am getting a few errors that I does not understand very well.

This is my code:

#!/usr/bin/python
import rospy
import roslib

# Messages
from std_msgs.msg import Float32
from std_msgs.msg import Bool

# Issue commands to the GoPiGo motors to achieve the target velocity
# Use a PID that compares the error based on encoder readings
class ControlsToMotors:
  def __init__(self):
    rospy.init_node('surp_controller')
    self.rate = rospy.get_param('~rate', 50)

    # Wheel can turn ~17 ticks per second which is approx 5.34 rad / s when motor_cmd = 255 ******Modify - calibrate according to the Stepper motor
    self.motor_max_angular_vel = rospy.get_param('~motor_max_angular_vel',5.32) 
    # Wheel can turn ~6 ticks per second which is approx 5.34 rad / s when motor_cmd = 125  ******Modify - calibrate according to the Stepper motor
    self.motor_min_angular_vel = rospy.get_param('~motor_min_angular_vel',1.28)
    # Corresponding motor commands
    self.motor_cmd_max = rospy.get_param('~motor_cmd_max',255)
    self.motor_cmd_min = rospy.get_param('~motor_cmd_min',110)

    self.R = rospy.get_param('~robot_wheel_radius', 0.03)
    self.gopigo_on = rospy.get_param('~gopigo_on',False)
    if self.gopigo_on:
      import gopigo
      import atexit
      atexit.register(gopigo.stop)
    # (Optional) Publish the computed angular velocity targets
    self.lwheel_angular_vel_target_pub = rospy.Publisher('lwheel_angular_vel_target', Float32, queue_size=10)
    self.rwheel_angular_vel_target_pub = rospy.Publisher('rwheel_angular_vel_target', Float32, queue_size=10)

    # (Optional) Publish the computed angular velocity control command
    self.lwheel_angular_vel_control_pub = rospy.Publisher('lwheel_angular_vel_control', Float32, queue_size=10)
    self.rwheel_angular_vel_control_pub = rospy.Publisher('rwheel_angular_vel_control', Float32, queue_size=10)

    # (Optional) Publish the computed angular velocity motor command
    self.lwheel_angular_vel_motor_pub = rospy.Publisher('lwheel_angular_vel_motor', Float32, queue_size=10)
    self.rwheel_angular_vel_motor_pub = rospy.Publisher('rwheel_angular_vel_motor', Float32, queue_size=10)

    # Publish commands to the arduino ***************************************
    self.motor1_cmd_pub = rospy.Publisher("motor1_cmd", Float32, queue_size=10)
    self.motor2_cmd_pub = rospy.Publisher("motor2_cmd", Float32, queue_size=10)
    
    # Publish motor direction to robot******************************
    self.motor1_dir_pub = rospy.Publisher("motor1_dir", bool, queue_size=10)
    self.motor2_dir_pub = rospy.Publisher("motor2_dir", bool, queue_size=10)

    # Read in encoders for PID control
    self.lwheel_angular_vel_enc_sub = rospy.Subscriber('lwheel_angular_vel_enc', Float32, self.lwheel_angular_vel_enc_callback)    
    self.rwheel_angular_vel_enc_sub = rospy.Subscriber('rwheel_angular_vel_enc', Float32, self.rwheel_angular_vel_enc_callback)    

    # Read in tangential velocity targets
    self.lwheel_tangent_vel_target_sub = rospy.Subscriber('lwheel_tangent_vel_target', Float32, self.lwheel_tangent_vel_target_callback)
    self.rwheel_tangent_vel_target_sub = rospy.Subscriber('rwheel_tangent_vel_target', Float32, self.rwheel_tangent_vel_target_callback)


    # Tangential velocity target
    self.lwheel_tangent_vel_target = 0;
    self.rwheel_tangent_vel_target = 0;

    # Angular velocity target
    self.lwheel_angular_vel_target = 0
    self.rwheel_angular_vel_target = 0
    
    # Angular velocity encoder readings
    self.lwheel_angular_vel_enc = 0
    self.rwheel_angular_vel_enc = 0

    # motor_cmd I dont know if it is necessary
    self.motor1_cmd = 0
    self.motor2_cmd = 0
    self.motor1_dir = True
    self.motor2_dir = True
    
  # ==================================================
  # Publish motor cmd to the robot
  # ==================================================
  def motor1_cmd_pub(self, msg):
    self.motor1_cmd = msg.data
  def motor2_cmd_pub(self, msg):
    self.motor2_cmd = msg.data
  def motor1_dir_pub(self, msg):
    self.motor1_dir = msg.data
  def motor2_dir_pub(self, msg):
    self.motor2_dir = msg.data
    
  # ==================================================
  # Read in tangential velocity targets
  # ==================================================
  def lwheel_tangent_vel_target_callback(self, msg):
      self.lwheel_tangent_vel_target = msg.data

  def rwheel_tangent_vel_target_callback(self, msg):
      self.rwheel_tangent_vel_target = msg.data

  # ==================================================
  # Read in encoder readings for PID
  # Consider for future iterations- modify for Back EMF, or use motor with encoder, or rely only on IMU
  # ==================================================
  def lwheel_angular_vel_enc_callback(self, msg):
    self.lwheel_angular_vel_enc = msg.data

  def rwheel_angular_vel_enc_callback(self, msg):
    self.rwheel_angular_vel_enc = msg.data

  # ==================================================
  # Update motor commands
  # ==================================================

  # Compute angular velocity target
  def tangentvel_2_angularvel(self,tangent_vel):
    # v = wr
    # v - tangential velocity (m/s)
    # w - angular velocity (rad/s)
    # r - radius of wheel (m)
    angular_vel = tangent_vel / self.R;
    return angular_vel


  # Mapping angular velocity targets to motor commands
  # Note: motor commands are ints between 0 - 255
  # We also assume motor commands are issues between motor_min_angular_vel and motor_max_angular_vel
  def angularvel_2_motorcmd(self, angular_vel_target):
    if angular_vel_target == 0: return 0;
    slope = (self.motor_cmd_max - self.motor_cmd_min) / (self.motor_max_angular_vel - self.motor_min_angular_vel)
    intercept = self.motor_cmd_max - slope * self.motor_max_angular_vel

    if angular_vel_target > 0: # positive angular velocity
      motor_cmd = slope * angular_vel_target + intercept
      if motor_cmd > self.motor_cmd_max: motor_cmd = self.motor_cmd_max
      if motor_cmd < self.motor_cmd_min: motor_cmd = self.motor_cmd_min
    
    else: # negative angular velocity
      motor_cmd = slope * abs(angular_vel_target) + intercept
      if motor_cmd > self.motor_cmd_max: motor_cmd = self.motor_cmd_max
      if motor_cmd < self.motor_cmd_min: motor_cmd = self.motor_cmd_min
      motor_cmd = -motor_cmd      

    return motor_cmd

  # Send motor command to robot
  # motor1 for left wheel. motor1(0, ?) tells wheel to move backwards. motor1(1, ?) tells wheel to move forwards
  # motor2 for right wheel.
  def motorcmd_2_robot(self, wheel='left', motor_command=0):
    if self.gopigo_on:
      motor_command_raw = int(abs(motor_command))
      if wheel == 'left':
        if motor_command >= 0: 
          self.motor1_cmd = motor_command_raw #use a publisher
          self.motor1_dir = True
        elif motor_command < 0: 
          self.motor1_cmd = motor_command_raw #use a publisher
          self.motor1_dir = False #I had to split in 2 publisher so it stay simple
      if wheel == 'right':
        if motor_command >= 0: 
          self.motor2_cmd = motor_command_raw #use a publisher
          self.motor2_dir = True
        elif motor_command < 0: 
          self.motor2_cmd = motor_command_raw #use a publisher
          self.motor2_dir = False

  def lwheel_update(self):
    # Compute target angular velocity
    self.lwheel_angular_vel_target = self.tangentvel_2_angularvel(self.lwheel_tangent_vel_target)
    self.lwheel_angular_vel_target_pub.publish(self.lwheel_angular_vel_target)
    
    self.lwheel_angular_vel_control_pub.publish(self.lwheel_angular_vel_target)

    # Compute motor command
    lwheel_motor_cmd = self.angularvel_2_motorcmd(self.lwheel_angular_vel_target)
    self.lwheel_angular_vel_motor_pub.publish(lwheel_motor_cmd)    

    # Send motor command
    self.motorcmd_2_robot('left',lwheel_motor_cmd)

  def rwheel_update(self):
    # Compute target angular velocity
    self.rwheel_angular_vel_target = self.tangentvel_2_angularvel(self.rwheel_tangent_vel_target)
    self.rwheel_angular_vel_target_pub.publish(self.rwheel_angular_vel_target)
    
    self.rwheel_angular_vel_control_pub.publish(self.rwheel_angular_vel_target)

    # Compute motor command
    rwheel_motor_cmd = self.angularvel_2_motorcmd(self.rwheel_angular_vel_target)
    self.rwheel_angular_vel_motor_pub.publish(rwheel_motor_cmd)    

    # Send motor command
    self.motorcmd_2_robot('right',rwheel_motor_cmd)

  #motor cmd publish
  def motor1_update(self):
    self.motor1_cmd_pub.publish(self.motor1_cmd)
    self.motor1_dir_pub.publish(self.motor1_dir)

  def motor2_update(self):
    self.motor2_cmd_pub.publish(self.motor2_cmd)
    self.motor1_dir_pub.publish(self.motor1_dir)

  # When given no commands for some time, do not move
  def spin(self):
    rospy.loginfo("Start surp_controller")
    rate = rospy.Rate(self.rate)
    
    rospy.on_shutdown(self.shutdown)

    while not rospy.is_shutdown():
      self.rwheel_update()
      self.lwheel_update()
      rate.sleep()
    rospy.spin();

  def shutdown(self):
    rospy.loginfo("Stop surp_controller")
      # Stop message
    self.lwheel_angular_vel_target_pub.publish(0)
    self.rwheel_angular_vel_target_pub.publish(0)
    self.lwheel_angular_vel_control_pub.publish(0)
    self.rwheel_angular_vel_control_pub.publish(0)
    self.lwheel_angular_vel_motor_pub.publish(0)
    self.rwheel_angular_vel_motor_pub.publish(0)
    rospy.sleep(1)        

def main():
  controls_to_motors = ControlsToMotors();
  controls_to_motors.spin()

if __name__ == '__main__':
    main(); 

When I try to run my code called: the surp_controller.py

surp_controller.py is completely based on gopigo_controller.py .

I receive the following errors:

File "/home/rmb/gopigo_ws/src/gopigo_controller/src/surp_controller.py", line 230, in <module>
    main(); 
  File "/home/rmb/gopigo_ws/src/gopigo_controller/src/surp_controller.py", line 226, in main
    controls_to_motors = ControlsToMotors();
  File "/home/rmb/gopigo_ws/src/gopigo_controller/src/surp_controller.py", line 47, in __init__
    self.motor1_dir_pub = rospy.Publisher("motor1_dir", bool, queue_size=10)
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/rospy/topics.py", line 842, in __init__
    super(Publisher, self).__init__(name, data_class, Registration.PUB)
  File "/opt/ros/kinetic/lib/python2.7/dist-packages/rospy/topics.py", line 144, in __init__
    raise ValueError("data_class [%s] is not a message data class"%data_class.__class__.__name__)
ValueError: data_class [type] is not a message data class

Originally posted by renanmb on ROS Answers with karma: 33 on 2017-07-30

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

 File "/home/rmb/gopigo_ws/src/gopigo_controller/src/surp_controller.py", line 47, in __init__
    self.motor1_dir_pub = rospy.Publisher("motor1_dir", bool, queue_size=10)

bool is not a message type.

Bool is.


Originally posted by gvdhoorn with karma: 86574 on 2017-07-30

This answer was ACCEPTED on the original site

Post score: 0


Original comments

Comment by renanmb on 2017-07-30:
Thanks. So every time I have a ValueError msg it is because I wrote something wrong? But how do I know what I wrote wrong?

Comment by gvdhoorn on 2017-07-30:\

every time I have a ValueError msg it is because I wrote something wrong

no. ValueError is a Python exception. You should probably read up on those.

how do I know what I wrote wrong?

By running your script. Python is an interpreted language, so no compiler to help you.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.