class DummyViconNode(object):
    """
    Example python node including reading parameters, publishers and subscribers, and timer.
    """
    def __init__(self):
        # Remember that init_node hasn't been called yet so only do stuff here that
        # doesn't require node handles etc.
        pass

    def start(self):
        rospy.init_node('python_node_example')
        self.tfb = TransformBroadcaster()
        self.init_params()
        self.init_publishers()
        self.init_timers()
        rospy.spin()
        
    def init_params(self):
        pass
#        self.param_one = rospy.get_param("~param_one", 100.0)
#        self.param_two = rospy.get_param("~param_two", False)
    
    def init_publishers(self):
        self.pub = rospy.Publisher('vicon_recv_direct/output', TransformStamped)
        
    def init_timers(self):
        self.vicon_timer = Timer(rospy.Duration(1/120.0), self.vicon_timer_callback) # Call at 10 Hz
                                          
    def vicon_timer_callback(self, event):
        msg = TransformStamped()
        msg.header.stamp = rospy.Time.now()
        msg.transform.rotation.w = 1.0
        self.pub.publish(msg)
        self.tfb.sendTransform((0,0,0), (0,0,0,1), rospy.Time.now(), '/pelican1/flyer_vicon', '/enu')
Ejemplo n.º 2
0
class RTbotController:
    def __init__(self, arduino):
        self.arduino = arduino
        self.stopped = False
        
        # Subscribe to rtbot_motors
        rospy.Subscriber("rtbot_motors", Int16, self.rtbotMotorsCallback)

        # Setup the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        
    def poll(self):
        (x, y, theta) = self.arduino.rtbot_read_odometry()

        quaternion = Quaternion()
        quaternion.x = 0.0 
        quaternion.y = 0.0
        quaternion.z = sin(theta / 2.0)
        quaternion.w = cos(theta / 2.0)
    
        # Create the odometry transform frame broadcaster.
        now = rospy.Time.now()
        self.odomBroadcaster.sendTransform(
            (x, y, 0), 
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            now,
            "base_link",
            "odom"
            )
    
        odom = Odometry()
        odom.header.frame_id = "odom"
        odom.child_frame_id = "base_link"
        odom.header.stamp = now
        odom.pose.pose.position.x = x
        odom.pose.pose.position.y = y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        
        # Possible issue: If we were commanding the robot via Twist messages
        # then we would have some sensible values to put here.  But by setting
        # the motor commands directly, we don't have access to plausible values
        # for the forward and angular speeds.  Does this even matter???
        #odom.twist.twist.linear.x = self.forwardSpeed
        odom.twist.twist.linear.x = 0
        odom.twist.twist.linear.y = 0
        #odom.twist.twist.angular.z = self.angularSpeed
        odom.twist.twist.angular.z = 0

        self.odomPub.publish(odom)

    def stop(self):
        self.stopped = True
        self.arduino.rtbot_set_motors(0)
            
    def rtbotMotorsCallback(self, msg):
        self.arduino.rtbot_set_motors(msg.data)    
Ejemplo n.º 3
0
class DiffTf:
    #############################################################################

    #############################################################################
    def __init__(self):
        #############################################################################
        rospy.init_node("switch_dom")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)

        #### parameters #######

        self.mapping_frame_id = rospy.get_param(
            '~mapping_frame_id',
            'odom_mapping')  # the name of the base frame of the robot
        self.nav_frame_id = rospy.get_param(
            '~nav_frame_id',
            'odom_nav')  # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param(
            '~odom_frame_id',
            'odom_comb')  # the name of the odometry reference frame

        self.odomPub = rospy.Publisher("odom_comb", Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        self.__mode = RobotMode.STARTING
        self.mode_sub_ = rospy.Subscriber('robot_mode', RobotMode,
                                          self.mode_callback)

        self.frame_id = self.nav_frame_id
        self.update()

    #############################################################################
    def spin(self):
        #############################################################################
        r = rospy.Rate(1000)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    #############################################################################
    def mode_callback(self, msg):
        #############################################################################
        if msg.code == RobotMode.MAPPING:
            self.frame_id = self.mapping_frame_id
            print 'mapping'
        else:
            self.frame_id = self.nav_frame_id
            print msg.code
        pass

    #############################################################################
    def update(self):
        #############################################################################
        # publish the odom information

        self.odomBroadcaster.sendTransform((0, 0, 0), (0.0, 0.0, 0.0, 1.0),
                                           rospy.Time.now(),
                                           self.odom_frame_id, self.frame_id)
Ejemplo n.º 4
0
class RTbotController:
    def __init__(self, arduino):
        self.arduino = arduino
        self.stopped = False

        # Subscribe to rtbot_motors
        rospy.Subscriber("rtbot_motors", Int16, self.rtbotMotorsCallback)

        # Setup the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

    def poll(self):
        (x, y, theta) = self.arduino.rtbot_read_odometry()

        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(theta / 2.0)
        quaternion.w = cos(theta / 2.0)

        # Create the odometry transform frame broadcaster.
        now = rospy.Time.now()
        self.odomBroadcaster.sendTransform(
            (x, y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w), now,
            "base_link", "odom")

        odom = Odometry()
        odom.header.frame_id = "odom"
        odom.child_frame_id = "base_link"
        odom.header.stamp = now
        odom.pose.pose.position.x = x
        odom.pose.pose.position.y = y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion

        # Possible issue: If we were commanding the robot via Twist messages
        # then we would have some sensible values to put here.  But by setting
        # the motor commands directly, we don't have access to plausible values
        # for the forward and angular speeds.  Does this even matter???
        #odom.twist.twist.linear.x = self.forwardSpeed
        odom.twist.twist.linear.x = 0
        odom.twist.twist.linear.y = 0
        #odom.twist.twist.angular.z = self.angularSpeed
        odom.twist.twist.angular.z = 0

        self.odomPub.publish(odom)

    def stop(self):
        self.stopped = True
        self.arduino.rtbot_set_motors(0)

    def rtbotMotorsCallback(self, msg):
        self.arduino.rtbot_set_motors(msg.data)
Ejemplo n.º 5
0
class OdometryPub:
    def __init__(self):
        self.base_frame_id = 'base_link'  # the name of the base frame of the robot
        self.odom_frame_id = 'odom'  # the name of the odometry reference frame

        # internal data
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        self.then = 0

        self.odomPub = rospy.Publisher("/odom", Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

    def update(self):
        global x
        global y
        global vx
        global vy
        global heading
        global heading_old

        if (self.then == 0):
            self.then = rospy.Time.now()
            return

        now = rospy.Time.now()
        elapsed = now - self.then
        self.then = now
        elapsed = elapsed.to_sec()

        # publish the odom information
        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(heading / 2)
        quaternion.w = cos(heading / 2)
        self.odomBroadcaster.sendTransform(
            (x, y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            rospy.Time.now(), self.base_frame_id, self.odom_frame_id)

        odom = Odometry()
        odom.header.stamp = now
        odom.header.frame_id = self.odom_frame_id
        odom.pose.pose.position.x = x
        odom.pose.pose.position.y = y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        odom.child_frame_id = self.base_frame_id
        odom.twist.twist.linear.x = vx
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = heading - heading_old
        self.odomPub.publish(odom)
Ejemplo n.º 6
0
def start():
    # ROS IMU 전달부 세팅 #
    #static_transform = rospy.get_param('~static_transform', [0, 0, 0, 0, 0, 0])
    fixed_frame = rospy.get_param('~fixed_frame', "base_footprint")
    frame_name = rospy.get_param('~frame_name', "imu")

    rospy.init_node('lsm303', anonymous=True)
    pub = rospy.Publisher('imu', Imu, queue_size=1)
    odomBroadcaster_imu = TransformBroadcaster()
    frequency = 5
    r = rospy.Rate(frequency)

    data = Imu()
    seq = 0

    print("[lsm303] loop start!")
    while not rospy.is_shutdown():
        data.header.frame_id = "imu"
        data.header.stamp = rospy.get_rostime()
        data.header.stamp = rospy.Time.now()
        data.header.seq = seq

        data.linear_acceleration.x, data.linear_acceleration.y, data.linear_acceleration.z = accel.acceleration
        #print("acceleration: {}".format(accel.acceleration))

        mag_x, mag_y, mag_z = mag.magnetic
        theta = -math.atan2(mag_y, mag_x)
        #print("theta: {}".format(theta))

        q = tf.transformations.quaternion_from_euler(0, 0, theta)
        data.orientation.x = q[0]
        data.orientation.y = q[1]
        data.orientation.z = q[2]
        data.orientation.w = q[3]

        odomBroadcaster_imu.sendTransform((0, 0, 0), (0, 0, 0, 1),
                                          rospy.Time.now(), frame_name,
                                          fixed_frame)

        #print("q(x,y,z,w): ({}, {}, {}, {})".format(data.orientation.x, data.orientation.y, data.orientation.z, data.orientation.w))

        data.angular_velocity.x = 0
        data.angular_velocity.y = 0
        data.angular_velocity.z = 0

        seq += 1
        pub.publish(data)
        r.sleep()

    print("[lsm303] program end")
class odomTransformer():
    def __init__(self):
        # naming
        rospy.init_node('Odom_Transformer', anonymous=False)

        # broadcaster
        self.tf_broadcaster = TransformBroadcaster()

        # subscribe the odom topic
        rospy.Subscriber('odom', Odometry, self.pub_odom_tf)

    def pub_odom_tf(self, msg):
        self.tf_broadcaster.sendTransform(
            (msg.pose.pose.position.x, msg.pose.pose.position.y, 0),
            (msg.pose.pose.orientation.x, msg.pose.pose.orientation.y,
             msg.pose.pose.orientation.z, msg.pose.pose.orientation.w),
            rospy.Time.now(), "base_footprint", "odom")
class DummyViconNode(object):
    """
    Example python node including reading parameters, publishers and subscribers, and timer.
    """
    def __init__(self):
        # Remember that init_node hasn't been called yet so only do stuff here that
        # doesn't require node handles etc.
        pass

    def start(self):
        rospy.init_node('python_node_example')
        self.tfb = TransformBroadcaster()
        self.init_params()
        self.init_publishers()
        self.init_timers()
        rospy.spin()
        
    def init_params(self):
        pass
        self.tf_ref_frame_id = rospy.get_param("~tf_ref_frame_id", "/enu")
        self.tf_tracked_frame_id = rospy.get_param("~tf_tracked_frame_id", "/pelican1/flyer_vicon")
        self.dummy_position = rospy.get_param("~dummy_position", (0.0, -0.3593, -0.05))
        self.dummy_orientation = rospy.get_param("~dummy_orientation", (0.5, 0.5, -0.5, 0.5)) # xyzw
        self.enable_tf_broadcast = rospy.get_param("~enable_tf_broadcast", False)
        
#        self.param_two = rospy.get_param("~param_two", False)
    
    def init_publishers(self):
        self.pub = rospy.Publisher('vicon_recv_direct/output', TransformStamped)
        
    def init_timers(self):
        self.vicon_timer = Timer(rospy.Duration(1/120.0), self.vicon_timer_callback) # Call at 10 Hz
                                          
    def vicon_timer_callback(self, event):
        msg = TransformStamped()
        msg.header.stamp = rospy.Time.now()
        msg.header.frame_id = self.tf_ref_frame_id
        msg.child_frame_id = self.tf_tracked_frame_id
        msg.transform.translation.x, msg.transform.translation.y, msg.transform.translation.z = self.dummy_position
        (msg.transform.rotation.x, msg.transform.rotation.y, 
         msg.transform.rotation.z, msg.transform.rotation.w) = self.dummy_orientation
        self.pub.publish(msg)
        if self.enable_tf_broadcast:
            self.tfb.sendTransform(self.dummy_position, self.dummy_orientation, 
                                   rospy.Time.now(), self.tf_tracked_frame_id, self.tf_ref_frame_id)
Ejemplo n.º 9
0
class Hector_Pose_2_Odom():
    def __init__(self):

        # ros
        rospy.Subscriber("/slam_out_pose", PoseStamped, self.slam_out_pose_cb)
        #self.odomPub = rospy.Publisher("odom", Odometry, queue_size=3)
        self.odomBroadcaster = TransformBroadcaster()

        self.base_frame_id = "base_footprint"
        self.odom_frame_id = "odom"

        rospy.loginfo("Init Hector_Pose_2_TF_Odom Finish!")

    def slam_out_pose_cb(self, req):
        orientation = req.pose.orientation

        self.odomBroadcaster.sendTransform(
            (req.pose.position.x, req.pose.position.y, 0),
            (orientation.x, orientation.y, orientation.z, orientation.w),
            rospy.Time.now(), self.base_frame_id, self.odom_frame_id)
Ejemplo n.º 10
0
class MockLocalization():
    def __init__(self):
        rospy.init_node("mock_localization")
        nodename = rospy.get_name()

        self.rate = rospy.get_param("~rate", 20)
        rospy.Subscriber('initialpose', PoseWithCovarianceStamped, self.poseCallback)
        self.pose = Pose()
        self.pose.position.x = 0
        self.pose.position.y = 0
        self.pose.position.z = 0
        quat = tf.transformations.quaternion_from_euler(0,0,0)
        self.pose.orientation.x = quat[0]
        self.pose.orientation.y = quat[1]
        self.pose.orientation.z = quat[2]
        self.pose.orientation.w = quat[3]
        self.broadcaster = TransformBroadcaster()

    def spin(self):
        r = rospy.Rate(self.rate)
        
        while(not rospy.is_shutdown()):
            self.broadcaster.sendTransform(
                (self.pose.position.x, self.pose.position.y, self.pose.position.z),
                (self.pose.orientation.x, self.pose.orientation.y, self.pose.orientation.z, self.pose.orientation.w),
                rospy.Time.now(),
                'odom',
                'map'
                )
            r.sleep()


    def poseCallback(self,msg):
        self.pose.position.x = msg.pose.pose - self.pose.position.x
		self.pose.position.y = msg.pose.pose - self.pose.position.y
		self.pose.position.z = msg.pose.pose - self.pose.position.z
Ejemplo n.º 11
0
class DiffTf:
#############################################################################

    #############################################################################
    def __init__(self):
    #############################################################################
        rospy.init_node("diff_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)
        
        #### parameters #######
        self.rate = rospy.get_param('~rate',10.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param('ticks_meter', 50))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param('~base_width', 0.245)) # The wheel base width in meters
        
        self.base_frame_id = rospy.get_param('~base_frame_id','base_link') # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param('~odom_frame_id', 'odom') # the name of the odometry reference frame
        self.world_frame_id = rospy.get_param('~world_frame_id', 'world') # the name of the world reference frame
        self.use_laser_scan_matcher = rospy.get_param("use_laser_scan_matcher", False)
        
        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param('wheel_low_wrap', (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min )
        self.encoder_high_wrap = rospy.get_param('wheel_high_wrap', (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min )
 
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = rospy.Time.now() + self.t_delta
        
        # internal data
        self.enc_left = None        # wheel encoder readings
        self.enc_right = None
        self.left = 0               # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0                  # position in xy plane 
        self.y = 0
        self.th = 0
        self.dx = 0                 # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()
        
        # subscriptions
        self.covariance = [
            0.1, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.1, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.1, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.1, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.1, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.0, 0.1
        ]
        rospy.Subscriber("lwheel", Int16, self.lwheelCallback)
        rospy.Subscriber("rwheel", Int16, self.rwheelCallback)
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

        self.listener = tf.TransformListener()

        rospy.Subscriber("pose2D", Pose2D, self.pose_callback, queue_size=1)
        

    #############################################################################
    def spin(self):
    #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    def update_from_laser_scan_matcher(self):
        if not self.listener.canTransform(self.base_frame_id, self.world_frame_id,
                rospy.Time(0)):
            rospy.logwarn("Transform not available %s -> %s", "/%s" % (self.base_frame_id), "/%s" % (self.world_frame_id))
            return
        (trans, rot) = self.listener.lookupTransform("/%s" % (self.base_frame_id), "/%s" % (self.world_frame_id), rospy.Time(0))
        #rospy.loginfo("Fixing odom x: %f y: %f th: %f -> x: %f y %f (%s %s)", self.x, self.y, self.th, trans[0], trans[1], trans, rot)

        self.x = trans[0]
        self.y = trans[1]
        self.th = asin(rot[2]) * 2

    def pose_callback(self, data):
        rospy.logdebug("Odom x: %f y: %f th: %f --- Pose x: %f y %f th: %f", self.x, self.y, self.th, data.x, data.y, data.theta)

        if self.use_laser_scan_matcher:
            self.x = data.x
            self.y = data.y
            self.th = data.theta
     
    #############################################################################
    def update(self):
    #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            #if self.use_laser_scan_matcher:
            #    self.update_from_laser_scan_matcher()

            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()
            
            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right
           
            # distance traveled is the average of the two wheels 
            d = ( d_left + d_right ) / 2
            # this approximation works (in radians) for small angles
            th = ( d_right - d_left ) / self.base_width
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed
           
             
            if (d != 0):
                # calculate distance traveled in x and y
                x = cos( th ) * d
                y = -sin( th ) * d
                # calculate the final position of the robot
                self.x = self.x + ( cos( self.th ) * x - sin( self.th ) * y )
                self.y = self.y + ( sin( self.th ) * x + cos( self.th ) * y )
            if( th != 0):
                self.th = self.th + th
                
            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin( self.th / 2 )
            quaternion.w = cos( self.th / 2 )

            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.pose.covariance = self.covariance
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            odom.twist.covariance = self.covariance
            self.odomPub.publish(odom)
            
            


    #############################################################################
    def lwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1
            
        if (enc > self.encoder_high_wrap and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1
            
        self.left = 1.0 * (enc + self.lmult * (self.encoder_max - self.encoder_min)) 
        self.prev_lencoder = enc
        
    #############################################################################
    def rwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if(enc < self.encoder_low_wrap and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1
        
        if(enc > self.encoder_high_wrap and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1
            
        self.right = 1.0 * (enc + self.rmult * (self.encoder_max - self.encoder_min))
        self.prev_rencoder = enc
Ejemplo n.º 12
0
class OdomPub():
    def __init__(self):
        rospy.init_node("odom_pub")
        nodename = rospy.get_name()

        self.base_width = rospy.get_param("~base_width", 0.11)
        self.ticks_meter = rospy.get_param("~ticks_meter", 1130)
        self.base_frame_id = rospy.get_param("~base_frame_id", "base_link")
        self.odom_frame_id = rospy.get_param("~odom_frame_id", "odom")
        self.rate = rospy.get_param("~rate", 20)

        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

        rospy.Subscriber('lticks', Int32, self.lticksCallback)
        rospy.Subscriber('rticks', Int32, self.rticksCallback)

        self.lticks = 0
        self.rticks = 0
        self.lastticks_l = 0
        self.lastticks_r = 0
        self.x = 0
        self.y = 0
        self.th = 0

    def spin(self):
        r = rospy.Rate(self.rate)
        self.last = rospy.Time.now()

        while not rospy.is_shutdown():
            self.spinOnce()
            r.sleep()

    def spinOnce(self):
        now = rospy.Time.now()
        dT = now - self.last
        dT = dT.to_sec()
        self.last = now

        d_left = float(self.lticks - self.lastticks_l) / self.ticks_meter
        d_right = float(self.rticks - self.lastticks_r) / self.ticks_meter
        self.lastticks_l = self.lticks
        self.lastticks_r = self.rticks

        d = (d_left + d_right) / 2
        th = (d_right - d_left) / self.base_width

        self.dx = d / dT
        self.dr = th / dT

        if (d != 0):
            # calculate distance traveled in x and y
            x = cos(th) * d
            y = -sin(th) * d
            # calculate the final position of the robot
            self.x = self.x + (cos(self.th) * x - sin(self.th) * y)
            self.y = self.y + (sin(self.th) * x + cos(self.th) * y)
        if (th != 0):
            self.th = self.th + th

        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(self.th / 2)
        quaternion.w = cos(self.th / 2)
        self.odomBroadcaster.sendTransform(
            (self.x, self.y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w), now,
            self.base_frame_id, self.odom_frame_id)

        odom = Odometry()
        odom.header.stamp = now
        odom.header.frame_id = self.odom_frame_id
        odom.pose.pose.position.x = self.x
        odom.pose.pose.position.y = self.y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        odom.child_frame_id = self.base_frame_id
        odom.twist.twist.linear.x = self.dx
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = self.dr
        self.odomPub.publish(odom)

    def lticksCallback(self, msg):
        self.lticks = msg.data
        pass

    def rticksCallback(self, msg):
        self.rticks = msg.data
        pass
Ejemplo n.º 13
0
class HCRNode:
    def __init__(self):
        """ Start up connection to the HCR Robot. """
        rospy.init_node('hcr')

        self.port = rospy.get_param('~port', ARDUINO_PORT)
        rospy.loginfo("Using port: %s" % (self.port))

        self.robot = hcr(self.port)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_vel = [0, 0]

    def spin(self):
        encoders = [0, 0]

        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        then = rospy.Time.now()

        odom = Odometry(header=rospy.Header(frame_id="odom"),
                        child_frame_id='base_link')

        # main loop of driver
        r = rospy.Rate(5)
        while not rospy.is_shutdown():
            odom.header.stamp = rospy.Time.now()
            # get motor velocity values
            vr, vl = self.robot.getMotors()

            # send updated movement commands
            self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1])

            # now update position information
            dt = (odom.header.stamp - then).to_sec()
            then = odom.header.stamp

            #odometry navigation
            omegaRight = vr / WHEELS_RAD
            omegaLeft = vl / WHEELS_RAD
            linear_velocity = (WHEELS_RAD / 2) * (omegaRight + omegaLeft)
            angular_velocity = (WHEELS_RAD / WHEELS_DIST) * (omegaRight -
                                                             omegaLeft)
            self.th += (angular_velocity * dt)
            self.th = normalize_angle(self.th)
            self.x += linear_velocity * cos(self.th) * dt
            self.y += linear_velocity * sin(self.th) * dt

            # prepare tf from base_link to odom
            quaternion = Quaternion()
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)

            # prepare odometry
            #odom.header.stamp = rospy.Time.now()
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = linear_velocity
            odom.twist.twist.angular.z = angular_velocity

            # publish everything
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w), then,
                "base_link", "odom")
            self.odomPub.publish(odom)

            # wait, then do it again
            r.sleep()

        # shut down
        self.robot.stop()

    def cmdVelCb(self, req):
        vLinear = req.linear.x
        vAngular = req.angular.z
        vr = ((2 * vLinear) + (WHEELS_DIST * vAngular)) / 2
        vl = ((2 * vLinear) - (WHEELS_DIST * vAngular)) / 2
        k = max(abs(vr), abs(vl))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            vr = vr * MAX_SPEED / k
            vl = vl * MAX_SPEED / k
        self.cmd_vel = [round(vr, 1), round(vl, 1)]
Ejemplo n.º 14
0
class BaseController:
    def __init__(self, arduino):
        self.arduino = arduino
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        self.timeout = rospy.get_param('~base_controller_timeout', 1.0)
        self.stopped = False

        pid_params = dict()
        pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", "")
        pid_params['wheel_track'] = rospy.get_param("~wheel_track", "")
        pid_params['encoder_resolution'] = rospy.get_param(
            "~encoder_resolution", "")
        pid_params['gear_reduction'] = rospy.get_param("~gear_reduction", 1.0)
        pid_params['Kp'] = rospy.get_param("~Kp", 20)
        pid_params['Kd'] = rospy.get_param("~Kd", 12)
        pid_params['Ki'] = rospy.get_param("~Ki", 0)
        pid_params['Ko'] = rospy.get_param("~Ko", 50)

        self.accel_limit = rospy.get_param('~accel_limit', 0.1)
        self.motors_reversed = rospy.get_param("~motors_reversed", False)

        # Used to Determin which cmd_vel to listen to
        self.cmdvel2 = False
        # Set up PID parameters and check for missing values
        self.setup_pid(pid_params)

        # How many encoder ticks are there per meter?
        self.ticks_per_meter = self.encoder_resolution * self.gear_reduction / (
            self.wheel_diameter * pi)

        # What is the maximum acceleration we will tolerate when changing wheel speeds?
        self.max_accel = self.accel_limit * self.ticks_per_meter / self.rate

        # Track how often we get a bad encoder count (if any)
        self.bad_encoder_count = 0

        now = rospy.Time.now()
        self.then = now  # time for determining dx/dy
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = now + self.t_delta

        # internal data
        self.enc_left = None  # encoder readings
        self.enc_right = None
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0  # rotation in radians
        self.v_left = 0
        self.v_right = 0
        self.v_des_left = 0  # cmd_vel setpoint
        self.v_des_right = 0
        self.last_cmd_vel = now

        # subscriptions
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)
        rospy.Subscriber("cmd_vel2", Twist, self.cmdVel2Callback)

        # Clear any old odometry info
        self.arduino.reset_encoders()

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

        rospy.loginfo("Started base controller for a base of " +
                      str(self.wheel_track) + "m wide with " +
                      str(self.encoder_resolution) + " ticks per rev")
        rospy.loginfo("Publishing odometry data at: " + str(self.rate) + " Hz")

    def setup_pid(self, pid_params):
        # Check to see if any PID parameters are missing
        missing_params = False
        for param in pid_params:
            if pid_params[param] == "":
                print("*** PID Parameter " + param + " is missing. ***")
                missing_params = True

        if missing_params:
            os._exit(1)

        self.wheel_diameter = pid_params['wheel_diameter']
        self.wheel_track = pid_params['wheel_track']
        self.encoder_resolution = pid_params['encoder_resolution']
        self.gear_reduction = pid_params['gear_reduction']

        self.Kp = pid_params['Kp']
        self.Kd = pid_params['Kd']
        self.Ki = pid_params['Ki']
        self.Ko = pid_params['Ko']

        self.arduino.update_pid(self.Kp, self.Kd, self.Ki, self.Ko)

    def poll(self):
        now = rospy.Time.now()
        if now > self.t_next:
            # Read the encoders
            try:
                left_enc, right_enc = self.arduino.get_encoder_counts()
            except:
                self.bad_encoder_count += 1
                rospy.logerr("Encoder exception count: " +
                             str(self.bad_encoder_count))
                return

            dt = now - self.then
            self.then = now
            dt = dt.to_sec()

            # calculate odometry
            if self.enc_left == None:
                dright = 0
                dleft = 0
            else:
                dright = (right_enc - self.enc_right) / self.ticks_per_meter
                dleft = (left_enc - self.enc_left) / self.ticks_per_meter

            self.enc_right = right_enc
            self.enc_left = left_enc

            dxy_ave = (dright + dleft) / 2.0
            dth = (dright - dleft) / self.wheel_track
            vxy = dxy_ave / dt
            vth = dth / dt

            if (dxy_ave != 0):
                dx = cos(dth) * dxy_ave
                dy = -sin(dth) * dxy_ave
                self.x += (cos(self.th) * dx - sin(self.th) * dy)
                self.y += (sin(self.th) * dx + cos(self.th) * dy)

            if (dth != 0):
                self.th += dth

            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)

            # Create the odometry transform frame broadcaster.
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(), "base_link", "odom")

            odom = Odometry()
            odom.header.frame_id = "odom"
            odom.child_frame_id = "base_link"
            odom.header.stamp = now
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = vxy
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = vth

            self.odomPub.publish(odom)

            if now > (self.last_cmd_vel + rospy.Duration(self.timeout)):
                self.v_des_left = 0
                self.v_des_right = 0

            if self.v_left < self.v_des_left:
                self.v_left += self.max_accel
                if self.v_left > self.v_des_left:
                    self.v_left = self.v_des_left
            else:
                self.v_left -= self.max_accel
                if self.v_left < self.v_des_left:
                    self.v_left = self.v_des_left

            if self.v_right < self.v_des_right:
                self.v_right += self.max_accel
                if self.v_right > self.v_des_right:
                    self.v_right = self.v_des_right
            else:
                self.v_right -= self.max_accel
                if self.v_right < self.v_des_right:
                    self.v_right = self.v_des_right

            # Set motor speeds in encoder ticks per PID loop
            if not self.stopped:
                self.arduino.drive(self.v_left, self.v_right)

            self.t_next = now + self.t_delta

    def stop(self):
        self.stopped = True
        self.arduino.drive(0, 0)

    def cmdVelCallback(self, req):
        #check if we are using cmd_vel2 at the moment
        if self.cmdvel2:
            return
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()

        x = req.linear.x  # m/s
        th = req.angular.z  # rad/s

        if x == 0:
            # Turn in place
            right = th * self.wheel_track * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track * self.gear_reduction / 2.0
            right = x + th * self.wheel_track * self.gear_reduction / 2.0

        self.v_des_left = int(left * self.ticks_per_meter /
                              self.arduino.PID_RATE)
        self.v_des_right = int(right * self.ticks_per_meter /
                               self.arduino.PID_RATE)

    def cmdVel2Callback(self, req):
        # Got a request, shut off cmd_vel
        self.cmdvel2 = True
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()

        x = req.linear.x  # m/s
        th = req.angular.z  # rad/s

        if x == 0:
            # if we are not turning in place, then go back to cmd_vel
            if th == 0:
                self.cmdvel2 = False
            # Turn in place
            right = th * self.wheel_track * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track * self.gear_reduction / 2.0
            right = x + th * self.wheel_track * self.gear_reduction / 2.0

        self.v_des_left = int(left * self.ticks_per_meter /
                              self.arduino.PID_RATE)
        self.v_des_right = int(right * self.ticks_per_meter /
                               self.arduino.PID_RATE)
class BaseController:
    def __init__(self, arduino, base_frame, name='base_controller'):
        self.arduino = arduino
        self.name = name
        self.base_frame = base_frame
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        self.timeout = rospy.get_param("~base_controller_timeout", 1.0)
        self.odom_linear_scale_correction = rospy.get_param("~odom_linear_scale_correction", 1.0)
        self.odom_angular_scale_correction = rospy.get_param("~odom_angular_scale_correction", 1.0)
        self.use_imu_heading = rospy.get_param("~use_imu_heading", False)
        self.publish_odom_base_transform = rospy.get_param("~publish_odom_base_transform", True)

        self.stopped = False
        self.current_speed = Twist()
                 
        pid_params = dict()
        pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", "")
        pid_params['wheel_track'] = rospy.get_param("~wheel_track", "")
        pid_params['encoder_resolution'] = rospy.get_param("~encoder_resolution", "")
        pid_params['gear_reduction'] = rospy.get_param("~gear_reduction", 1.0)
        pid_params['Kp'] = rospy.get_param("~Kp", 20)
        pid_params['Kd'] = rospy.get_param("~Kd", 12)
        pid_params['Ki'] = rospy.get_param("~Ki", 0)
        pid_params['Ko'] = rospy.get_param("~Ko", 50)
        
        self.accel_limit = rospy.get_param('~accel_limit', 1.0)
        self.motors_reversed = rospy.get_param("~motors_reversed", False)
        self.detect_enc_jump_error = rospy.get_param("~detect_enc_jump_error", False)
        self.enc_jump_error_threshold = rospy.get_param("~enc_jump_error_threshold", 1000)

        # Default error threshold (percent) before getting a diagnostics warning
        self.base_diagnotics_error_threshold = rospy.get_param("~base_diagnotics_error_threshold", 10)

        # Diagnostics update rate
        self.base_diagnotics_rate = rospy.get_param("~base_diagnotics_rate", 1.0)

        # Create the diagnostics updater for the Arduino device
        self.diagnostics = DiagnosticsUpdater(self, self.name, self.base_diagnotics_error_threshold, self.base_diagnotics_rate)

        # Set up PID parameters and check for missing values
        self.setup_pid(pid_params)

        # How many encoder ticks are there per meter?
        self.ticks_per_meter = self.encoder_resolution * self.gear_reduction  / (self.wheel_diameter * pi)

        # What is the maximum acceleration we will tolerate when changing wheel speeds?
        self.max_accel = self.accel_limit * self.ticks_per_meter / self.rate

        # Track how often we get a bad encoder count (if any)
        self.bad_encoder_count = 0

        now = rospy.Time.now()    
        self.then = now # time for determining dx/dy
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = now + self.t_delta

        # Internal data        
        self.enc_left = None            # encoder readings
        self.enc_right = None
        self.x = 0                      # position in xy plane
        self.y = 0
        self.th = 0                     # rotation in radians
        self.v_left = 0
        self.v_right = 0
        self.v_des_left = 0             # cmd_vel setpoint
        self.v_des_right = 0
        self.last_cmd_vel = now

        # Subscriptions
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)

        # Clear any old odometry info
        self.arduino.reset_encoders()

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=5)
        self.odomBroadcaster = TransformBroadcaster()

        rospy.loginfo("Started base controller for a base of " + str(self.wheel_track) + "m wide with " + str(self.encoder_resolution) + " ticks per rev")
        rospy.loginfo("Publishing odometry data at: " + str(self.rate) + " Hz using " + str(self.base_frame) + " as base frame")
        
    def setup_pid(self, pid_params):
        # Check to see if any PID parameters are missing
        missing_params = False
        for param in pid_params:
            if pid_params[param] is None or pid_params[param] == "":
                print("*** PID Parameter " + param + " is missing. ***")
                missing_params = True
        
        if missing_params:
            os._exit(1)
                
        self.wheel_diameter = pid_params['wheel_diameter']
        self.wheel_track = pid_params['wheel_track']
        self.encoder_resolution = pid_params['encoder_resolution']
        self.gear_reduction = pid_params['gear_reduction']
        
        self.Kp = pid_params['Kp']
        self.Kd = pid_params['Kd']
        self.Ki = pid_params['Ki']
        self.Ko = pid_params['Ko']
        
        if self.arduino.update_pid(self.Kp, self.Kd, self.Ki, self.Ko):
            rospy.loginfo("PID parameters update to: Kp=%d, Kd=%d, Ki=%d, Ko=%d" %(self.Kp, self.Kd, self.Ki, self.Ko))
        else:
            rospy.logerr("Updating PID parameters failed!")

    def poll(self):
        now = rospy.Time.now()
        if now > self.t_next:
            # Read the encoders
            try:
                self.diagnostics.reads += 1
                self.diagnostics.total_reads += 1
                left_enc, right_enc = self.arduino.get_encoder_counts()
                self.diagnostics.freq_diag.tick()
            except:
                self.diagnostics.errors += 1
                self.bad_encoder_count += 1
                rospy.logerr("Encoder exception count: " + str(self.bad_encoder_count))
                return

            # Check for jumps in encoder readings
            if self.detect_enc_jump_error:
                try:
                    #rospy.loginfo("Left: %d LEFT: %d Right: %d RIGHT: %d", left_enc, self.enc_left, right_enc, self.enc_right)
                    enc_jump_error = False
                    if abs(right_enc - self.enc_right) > self.enc_jump_error_threshold:
                        self.diagnostics.errors += 1
                        self.bad_encoder_count += 1
                        rospy.logerr("RIGHT encoder jump error from %d to %d", self.enc_right, right_enc)
                        self.enc_right = right_enc
                        enc_jump_error = True

                    if abs(left_enc - self.enc_left) > self.enc_jump_error_threshold:
                        self.diagnostics.errors += 1
                        self.bad_encoder_count += 1
                        rospy.logerr("LEFT encoder jump error from %d to %d", self.enc_left, left_enc)
                        self.enc_left = left_enc
                        enc_jump_error = True

                    if enc_jump_error:
                        return
                except:
                    pass

            dt = now - self.then
            self.then = now
            dt = dt.to_sec()
            
            # Calculate odometry
            if self.enc_left == None:
                dright = 0
                dleft = 0
            else:
                dright = (right_enc - self.enc_right) / self.ticks_per_meter
                dleft = (left_enc - self.enc_left) / self.ticks_per_meter

            self.enc_right = right_enc
            self.enc_left = left_enc
            
            dxy_ave = self.odom_linear_scale_correction * (dright + dleft) / 2.0
            dth = self.odom_angular_scale_correction * (dright - dleft) / float(self.wheel_track)
            vxy = dxy_ave / dt
            vth = dth / dt
                
            if (dxy_ave != 0):
                dx = cos(dth) * dxy_ave
                dy = -sin(dth) * dxy_ave
                self.x += (cos(self.th) * dx - sin(self.th) * dy)
                self.y += (sin(self.th) * dx + cos(self.th) * dy)
    
            if (dth != 0):
                self.th += dth 
    
            quaternion = Quaternion()
            quaternion.x = 0.0 
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)
    
            # Create the odometry transform frame broadcaster.
            if self.publish_odom_base_transform:
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0), 
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(),
                    self.base_frame,
                    "odom"
                    )
    
            odom = Odometry()
            odom.header.frame_id = "odom"
            odom.child_frame_id = self.base_frame
            odom.header.stamp = now
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = vxy
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = vth
            
            self.current_speed = Twist()
            self.current_speed.linear.x = vxy
            self.current_speed.angular.z = vth

            """
            Covariance values taken from Kobuki node odometry.cpp at:
            https://github.com/yujinrobot/kobuki/blob/indigo/kobuki_node/src/library/odometry.cpp
            
            Pose covariance (required by robot_pose_ekf) TODO: publish realistic values
            Odometry yaw covariance must be much bigger than the covariance provided
            by the imu, as the later takes much better measures
            """
            odom.pose.covariance[0]  = 0.1
            odom.pose.covariance[7]  = 0.1
            if self.use_imu_heading:
                #odom.pose.covariance[35] = 0.2
                odom.pose.covariance[35] = 0.05
            else:
                odom.pose.covariance[35] = 0.05
            
            odom.pose.covariance[14] = sys.float_info.max  # set a non-zero covariance on unused
            odom.pose.covariance[21] = sys.float_info.max  # dimensions (z, pitch and roll); this
            odom.pose.covariance[28] = sys.float_info.max  # is a requirement of robot_pose_ekf

            self.odomPub.publish(odom)
            
            if now > (self.last_cmd_vel + rospy.Duration(self.timeout)):
                self.v_des_left = 0
                self.v_des_right = 0
                
            if self.v_left < self.v_des_left:
                self.v_left += self.max_accel
                if self.v_left > self.v_des_left:
                    self.v_left = self.v_des_left
            else:
                self.v_left -= self.max_accel
                if self.v_left < self.v_des_left:
                    self.v_left = self.v_des_left
            
            if self.v_right < self.v_des_right:
                self.v_right += self.max_accel
                if self.v_right > self.v_des_right:
                    self.v_right = self.v_des_right
            else:
                self.v_right -= self.max_accel
                if self.v_right < self.v_des_right:
                    self.v_right = self.v_des_right
            
            # Set motor speeds in encoder ticks per PID loop
            if not self.stopped:
                self.arduino.drive(self.v_left, self.v_right)
                
            self.t_next = now + self.t_delta

    def stop(self):
        self.stopped = True
        self.arduino.drive(0, 0)
            
    def cmdVelCallback(self, req):
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()
        
        x = req.linear.x         # m/s
        th = req.angular.z       # rad/s

        if x == 0:
            # Turn in place
            right = th * self.wheel_track  * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track  * self.gear_reduction / 2.0
            right = x + th * self.wheel_track  * self.gear_reduction / 2.0
            
        self.v_des_left = int(left * self.ticks_per_meter / self.arduino.PID_RATE)
        self.v_des_right = int(right * self.ticks_per_meter / self.arduino.PID_RATE)
        
    def reset_odometry(self):
        self.x = 0.0
        self.y = 0.0
        self.th = 0.0
Ejemplo n.º 16
0
class DiffTf:
#############################################################################

    #############################################################################
    def __init__(self):
    #############################################################################
        rospy.init_node("diff_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)
        
        #### parameters #######
        self.rate = rospy.get_param('~rate',10.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param('ticks_meter', 282.5))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param('~base_width', 0.26)) # The wheel base width in meters
        
        self.base_frame_id = rospy.get_param('~base_frame_id','base_link') # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param('~odom_frame_id', 'odom') # the name of the odometry reference frame
        
        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param('wheel_low_wrap', (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min )
        self.encoder_high_wrap = rospy.get_param('wheel_high_wrap', (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min )
 

        
        self.lowLevelInits()
        
        # subscriptions
        rospy.Subscriber("lwheel", Int16, self.lwheelCallback)
        rospy.Subscriber("rwheel", Int16, self.rwheelCallback)
        rospy.Subscriber("Nav_State", UInt32, self.navState)
        self.odomPub = rospy.Publisher("odom", Odometry)
        self.odomBroadcaster = TransformBroadcaster()
    
    def lowLevelInits(self):
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = rospy.Time.now() + self.t_delta
        # internal data
        self.enc_left = None        # wheel encoder readings
        self.enc_right = None
        self.left = 0               # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0                  # position in xy plane 
        self.y = 0
        self.th = 0
        self.dx = 0                 # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()    
        
    #############################################################################
    def spin(self):
    #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    def navState(self, data):
      if data.data == 2:
        self.lowLevelInits()       
     
    #############################################################################
    def update(self):
    #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()
            
            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right
           
            # distance traveled is the average of the two wheels 
            d = ( d_left + d_right ) / 2
            # this approximation works (in radians) for small angles
            th = ( d_right - d_left ) / self.base_width
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed
           
             
            if (d != 0):
                # calculate distance traveled in x and y
                x = cos( th ) * d
                y = -sin( th ) * d
                # calculate the final position of the robot
                self.x = self.x + ( cos( self.th ) * x - sin( self.th ) * y )
                self.y = self.y + ( sin( self.th ) * x + cos( self.th ) * y )
            if( th != 0):
                self.th = self.th + th
                
            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin( self.th / 2 )
            quaternion.w = cos( self.th / 2 )
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )
            
            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)
            self.odomBroadcaster.sendTransform((0,0,0.23), (-0.500, 0.485, -0.500, 0.515), rospy.Time.now(), "camera", "base_link")
            
            


    #############################################################################
    def lwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1
            
        if (enc > self.encoder_high_wrap and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1
            
        self.left = 1.0 * (enc + self.lmult * (self.encoder_max - self.encoder_min)) 
        self.prev_lencoder = enc
        
    #############################################################################
    def rwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if(enc < self.encoder_low_wrap and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1
        
        if(enc > self.encoder_high_wrap and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1
            
        self.right = 1.0 * (enc + self.rmult * (self.encoder_max - self.encoder_min))
        self.prev_rencoder = enc
Ejemplo n.º 17
0
class CreateDriver:
    def __init__(self):
        port = rospy.get_param('~port', "/dev/ttyUSB0")
        self.create = Create(port)
        self.packetPub = rospy.Publisher('sensorPacket', SensorPacket)
        self.odomPub = rospy.Publisher('odom', Odometry)
        self.odomBroadcaster = TransformBroadcaster()
        self.fields = [
            'wheeldropCaster', 'wheeldropLeft', 'wheeldropRight', 'bumpLeft',
            'bumpRight', 'wall', 'cliffLeft', 'cliffFronLeft',
            'cliffFrontRight', 'cliffRight', 'virtualWall', 'infraredByte',
            'advance', 'play', 'distance', 'angle', 'chargingState', 'voltage',
            'current', 'batteryTemperature', 'batteryCharge',
            'batteryCapacity', 'wallSignal', 'cliffLeftSignal',
            'cliffFrontLeftSignal', 'cliffFrontRightSignal',
            'cliffRightSignal', 'homeBase', 'internalCharger', 'songNumber',
            'songPlaying', 'x', 'y', 'theta', 'chargeLevel'
        ]
        self.then = datetime.now()
        self.x = 0
        self.y = 0
        self.th = 0
        self.create.update = self.sense
        self.inDock = False
        self.chargeLevel = 0

    def start(self):
        self.create.start()
        self.then = datetime.now()

    def stop(self):
        self.create.stop()

    def sense(self):
        now = datetime.now()
        elapsed = now - self.then
        self.then = now
        elapsed = float(elapsed.seconds) + elapsed.microseconds / 1000000.
        d = self.create.d_distance / 1000.
        th = self.create.d_angle * pi / 180
        dx = d / elapsed
        dth = th / elapsed

        if (d != 0):
            x = cos(th) * d
            y = -sin(th) * d
            self.x = self.x + (cos(self.th) * x - sin(self.th) * y)
            self.y = self.y + (sin(self.th) * x + cos(self.th) * y)

        if (th != 0):
            self.th = self.th + th

        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(self.th / 2)
        quaternion.w = cos(self.th / 2)

        self.odomBroadcaster.sendTransform(
            (self.x, self.y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            rospy.Time.now(), "base_link", "odom")

        odom = Odometry()
        odom.header.stamp = rospy.Time.now()
        odom.header.frame_id = "odom"
        odom.pose.pose.position.x = self.x
        odom.pose.pose.position.y = self.y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion

        odom.child_frame_id = "base_link"
        odom.twist.twist.linear.x = dx
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = dth

        self.odomPub.publish(odom)

        packet = SensorPacket()
        for field in self.fields[:-4]:
            packet.__setattr__(field, self.create.__getattr__(field))

        self.chargeLevel = float(packet.batteryCharge) / float(
            packet.batteryCapacity)
        packet.__setattr__('x', self.x)
        packet.__setattr__('y', self.y)
        packet.__setattr__('theta', self.th)
        packet.__setattr__('chargeLevel', self.chargeLevel)
        self.packetPub.publish(packet)

        if packet.homeBase:
            self.inDock = True
        else:
            self.inDock = False

    def circle(self, req):
        self.create.forwardTurn(req.speed, req.radius)
        return CircleResponse(True)

    def demo(self, req):
        self.create.demo(req.demo)
        return DemoResponse(True)

    def leds(self, req):
        self.create.leds(req.advance, req.play, req.color, req.intensity)
        return LedsResponse(True)

    def tank(self, req):
        self.create.tank(req.left, req.right)
        return TankResponse(True)

    def turn(self, req):
        if (req.clear):
            self.create.clear()
        self.create.turn(req.turn)
        return TurnResponse(True)

    def dock(self, req):
        """ req.charge = 0: dock and charge 
                       = 1: wake up from charging
                       = 2: dock and wake up immediately """

        if req.charge == 2:
            self.create.restart()
            return DockResponse(True)

        self.create.brake()
        self.create.demo(1)
        while (not self.inDock):
            pass

        if req.charge == 0:
            rospy.sleep(3)
            self.create.restart()
        return DockResponse(True)

    """ Added summer 2012 """

    def opCode(self, opCode):
        self.create.send(opCode)

    def twist(self, req):
        x = req.linear.x * 1000.
        th = req.angular.z
        print(x, th)
        if (x == 0):
            th = th * 180 / pi
            speed = (8 * pi * th) / 9
            self.create.left(int(speed))
        elif (th == 0):
            x = int(x)
            self.create.tank(x, x)
        else:
            self.create.forwardTurn(int(x), int(x / th))

    def song(self, req):
        self.create.playFullSong(req.notes, req.durations)
        return SongResponse(True)
Ejemplo n.º 18
0
def main(argv):
    # prepare the proxy, listener
    global listener
    global vizpub
    rospy.init_node('contour_follow', anonymous=True)
    listener = tf.TransformListener()
    vizpub = rospy.Publisher("visualization_marker", Marker, queue_size=10)
    br = TransformBroadcaster()
    
    setSpeed(tcp=100, ori=30)
    setZone(0)
    # set the parameters
    limit = 10000  # number of data points to be collected
    ori = [0, 0.7071, 0.7071, 0]
    threshold = 0.3  # the threshold force for contact, need to be tuned
    z = 0.218   # the height above the table probe1: 0.29 probe2: 0.218
    probe_radis = 0.004745   # probe1: 0.00626/2 probe2: 0.004745
    step_size = 0.0002
    obj_des_wrt_vicon = [0,0,-(9.40/2/1000+14.15/2/1000),0,0,0,1]
    
    # visualize the block 
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    vizBlock(obj_des_wrt_vicon)
    rospy.sleep(0.1)
    
    # 0. move to startPos
    start_pos = [0.3, 0.06, z + 0.05]
    setCart(start_pos,ori)
    
    start_pos = [0.3, 0.06, z]
    setCart(start_pos,ori)
    curr_pos = start_pos
    # 0.1 zero the ft reading
    rospy.sleep(1)  
    setZero()
    rospy.sleep(3)
    
    # 1. move in -y direction till contact -> normal
    setSpeed(tcp=30, ori=30)
    direc = np.array([0, -step_size, 0])
    normal = [0,0,0]
    while True:
        curr_pos = np.array(curr_pos) + direc
        setCart(curr_pos, ori)
        # let the ft reads the force in static, not while pushing
        rospy.sleep(0.1)  
        ft = ftmsg2list(ROS_Wait_For_Msg('/netft_data', geometry_msgs.msg.WrenchStamped).getmsg())
        print '[ft explore]', ft
        # get box pose from vicon
        (box_pos, box_quat) = lookupTransform('base_link', 'vicon/SteelBlock/SteelBlock', listener)
        # correct box_pose
        box_pose_des_global =  mat2poselist( np.dot(poselist2mat(list(box_pos) + list(box_quat)), poselist2mat(obj_des_wrt_vicon)))
        print 'box_pose', box_pose_des_global
        
        # If in contact, break
        if norm(ft[0:2]) > threshold:
            # transform ft data to global frame
            ft_global = transformFt2Global(ft)
            ft_global[2] = 0  # we don't want noise from z
            normal = ft_global[0:3] / norm(ft_global)
            break
    #pause()
    
    # 2. use the normal to move along the block
    setSpeed(tcp=20, ori=30)
    index = 0
    contact_pts = []
    contact_nms = []
    all_contact = []
    while True:
        # 2.1 move 
        direc = np.dot(tfm.euler_matrix(0,0,2) , normal.tolist() + [1])[0:3]
        curr_pos = np.array(curr_pos) + direc * step_size
        setCart(curr_pos, ori)
        
        # let the ft reads the force in static, not while pushing
        rospy.sleep(0.1)
        ft = getAveragedFT()
        print index #, '[ft explore]', ft
        # get box pose from vicon
        (box_pos, box_quat) = lookupTransform('base_link', 'vicon/SteelBlock/SteelBlock', listener)
        # correct box_pose
        box_pose_des_global = mat2poselist( np.dot(poselist2mat(list(box_pos) + list(box_quat)), poselist2mat(obj_des_wrt_vicon)))
        #box_pose_des_global = list(box_pos) + list(box_quat)
        #print 'box_pose', box_pose_des_global
        
        vizBlock(obj_des_wrt_vicon)
        br.sendTransform(box_pose_des_global[0:3], box_pose_des_global[3:7], rospy.Time.now(), "SteelBlockDesired", "map")
        #print 'box_pos', box_pos, 'box_quat', box_quat
                
        if norm(ft[0:2]) > threshold:
            # transform ft data to global frame
            ft_global = transformFt2Global(ft)
            ft_global[2] = 0  # we don't want noise from z
            normal = ft_global[0:3] / norm(ft_global)
            contact_nms.append(normal.tolist())
            contact_pt = curr_pos - normal * probe_radis
            contact_pts.append(contact_pt.tolist())
            contact_pt[2] = 0.01
            vizPoint(contact_pt.tolist())
            vizArrow(contact_pt.tolist(), (contact_pt + normal * 0.1).tolist())
            # caution: matlab uses the other quaternion order: w x y z. Also the normal is in toward the object.
            all_contact.append(contact_pt.tolist()[0:2] + [0] + (-normal).tolist()[0:2] + [0] + box_pose_des_global[0:3] + box_pose_des_global[6:7] + box_pose_des_global[3:6] + curr_pos.tolist())
            index += 1
        
        if len(contact_pts) > limit:
            break
        
        if len(contact_pts) % 500 == 0:  # zero the ft offset, move away from block, zero it, then come back
            move_away_size = 0.01
            overshoot_size = 0 #0.0005
            setSpeed(tcp=5, ori=30)
            setCart(curr_pos + normal * move_away_size, ori)
            rospy.sleep(1)
            print 'bad ft:', getAveragedFT()
            setZero()
            rospy.sleep(3)
            setCart(curr_pos - normal * overshoot_size, ori)
            setSpeed(tcp=20, ori=30)
            
    
      #all_contact(1:2,:);  % x,y of contact position
      #all_contact(4:5,:);  % x,y contact normal
      #all_contact(7:9,:);  % box x,y
      #all_contact(10:13,:);  % box quaternion
      #all_contact(14:16,:);  % pusher position
    
    
    # save contact_nm and contact_pt as json file
    with open(os.environ['PNPUSHDATA_BASE']+'/all_contact_real.json', 'w') as outfile:
        json.dump({'contact_pts': contact_pts, 'contact_nms': contact_nms}, outfile)

    # save all_contact as mat file
    sio.savemat(os.environ['PNPUSHDATA_BASE']+'/all_contact_real.mat', {'all_contact': all_contact})
    
    setSpeed(tcp=100, ori=30)
    # 3. move back to startPos
    start_pos = [0.3, 0.06, z + 0.05]
    setCart(start_pos,ori)
Ejemplo n.º 19
0
class ThymioDriver(object):

    def frame_name(self, name):
        if self.tf_prefix:
            return '{self.tf_prefix}/{name}'.format(**locals())
        return name

    def change_config(self, config, level):
        # self.diff_factor = config.diff_factor
        # self.ticks2mm = config.ticks2mm
        self.motor_speed_deadband = config.motor_speed_deadband
        return config

    @property
    def motor_speed_deadband(self):
        return self._motor_speed_deadband

    @motor_speed_deadband.setter
    def motor_speed_deadband(self, value):
        self._motor_speed_deadband = value
        self.odom_msg.twist.covariance[0] = speed_cov = 0.5 * (value / 1000 / SPEED_COEF) ** 2
        self.odom_msg.twist.covariance[-1] = speed_cov / (self.axis ** 2)

    def __init__(self):
        rospy.init_node('thymio')

        # load script on the Thymio

        rospy.wait_for_service('aseba/get_node_list')
        get_aseba_nodes = rospy.ServiceProxy(
            'aseba/get_node_list', GetNodeList)

        while True:
            if 'thymio-II' in get_aseba_nodes().nodeList:
                break
            rospy.loginfo('Waiting for thymio node ...')
            rospy.sleep(1)

        rospy.wait_for_service('aseba/load_script')
        load_script = rospy.ServiceProxy('aseba/load_script', LoadScripts)
        default_script_path = os.path.join(
            roslib.packages.get_pkg_dir('thymio_driver'), 'aseba/thymio_ros.aesl')

        script_path = rospy.get_param('~script', default_script_path)

        rospy.loginfo("Load aseba script %s", script_path)

        load_script(script_path)

        # initialize parameters

        self.tf_prefix = rospy.get_param('tf_prefix', '')

        self.odom_frame = self.frame_name(rospy.get_param('~odom_frame', 'odom'))
        self.robot_frame = self.frame_name(rospy.get_param('~robot_frame', 'base_link'))

        self.x = 0
        self.y = 0
        self.th = 0
        self.then = rospy.Time.now()
        odom_rate = rospy.get_param('~odom_max_rate', -1)
        if odom_rate == 0:
            self.odom_min_period = -1
        else:
            self.odom_min_period = 1.0 / odom_rate
        self.odom_msg = Odometry(header=rospy.Header(frame_id=self.odom_frame),
                                 child_frame_id=self.robot_frame)

        self.odom_msg.pose.pose.position.z = 0
        self.odom_msg.pose.covariance[0] = -1
        self.odom_msg.header.stamp = rospy.Time.now()

        # subscribe to topics

        self.aseba_pub = rospy.Publisher(
            'aseba/events/set_speed', AsebaEvent, queue_size=1)

        self.left_wheel_angle = 0
        self.right_wheel_angle = 0

        self.axis = rospy.get_param('~axis_length', BASE_WIDTH / 1000.0)
        self.motor_speed_deadband = rospy.get_param('~motor_speed_deadband', 10)
        # self.ticks2mm = rospy.get_param('~ticks2mm', 1.0 / SPEED_COEF)
        # self.diff_factor = rospy.get_param('~diff_factor', 1.0)

        def_cal = [0.001 / SPEED_COEF, 0]

        left_wheel_calibration = rospy.get_param('~left_wheel_calibration/q', def_cal)

        self.left_wheel_speed, self.left_wheel_motor_speed = motor_speed_conversion(
            *left_wheel_calibration)
        rospy.loginfo('Init left wheel with calibration %s', left_wheel_calibration)

        right_wheel_calibration = rospy.get_param('~right_wheel_calibration/q', def_cal)
        self.right_wheel_speed, self.right_wheel_motor_speed = motor_speed_conversion(
            *right_wheel_calibration)

        rospy.loginfo('Init right wheel with calibration %s', right_wheel_calibration)

        left_wheel_joint = rospy.get_param('~left_wheel_joint', 'left_wheel_joint')
        right_wheel_joint = rospy.get_param('~right_wheel_joint', 'right_wheel_joint')

        self.wheel_state_msg = JointState()
        self.wheel_state_msg.name = [left_wheel_joint, right_wheel_joint]

        self.wheel_state_pub = rospy.Publisher('joint_states', JointState, queue_size=1)
        self.odom_pub = rospy.Publisher('odom', Odometry, queue_size=1)
        self.odom_broadcaster = TransformBroadcaster()

        rospy.Subscriber('aseba/events/odometry', AsebaEvent, self.on_aseba_odometry_event)
        rospy.Subscriber("cmd_vel", Twist, self.on_cmd_vel)

        self.buttons = Joy()
        self.buttons_pub = rospy.Publisher('buttons', Joy, queue_size=1)
        rospy.Subscriber("aseba/events/buttons", AsebaEvent, self.on_aseba_buttons_event)

        for button in BUTTONS:
            rospy.Subscriber('aseba/events/button_' + button,
                             AsebaEvent, self.on_aseba_button_event(button))

        proximity_range_min = rospy.get_param('~proximity/range_min', 0.0215)
        proximity_range_max = rospy.get_param('~proximity/range_min', 0.14)
        proximity_field_of_view = rospy.get_param('~proximity/field_of_view', 0.3)

        self.proximity_sensors = [{
            'publisher': rospy.Publisher('proximity/' + name, Range, queue_size=1),
            'msg': Range(
                header=rospy.Header(
                    frame_id=self.frame_name('proximity_{name}_link'.format(name=name))),
                radiation_type=Range.INFRARED,
                field_of_view=proximity_field_of_view,
                min_range=proximity_range_min,
                max_range=proximity_range_max)}
            for name in PROXIMITY_NAMES]

        self.proximityToLaserPublisher = rospy.Publisher(
            'proximity/laser', LaserScan, queue_size=1)
        self.proximityToLaser = LaserScan(
            header=rospy.Header(frame_id=self.frame_name('laser_link')),
            angle_min=-0.64, angle_max=0.64, angle_increment=0.32,
            time_increment=0, scan_time=0, range_min=proximity_range_min + 0.08,
            range_max=proximity_range_max + 0.08)
        rospy.Subscriber('aseba/events/proximity', AsebaEvent, self.on_aseba_proximity_event)

        self.ground_sensors = [{
            'publisher': rospy.Publisher('ground/' + name, Range, queue_size=1),
            'msg': Range(
                header=rospy.Header(
                    frame_id=self.frame_name('ground_{name}_link'.format(name=name))),
                radiation_type=Range.INFRARED, field_of_view=proximity_field_of_view,
                min_range=(GROUND_MIN_RANGE / 1000.0), max_range=(GROUND_MAX_RANGE / 1000.0))
        } for name in GROUND_NAMES]

        ground_threshold = rospy.get_param('~ground/threshold', 200)

        rospy.Subscriber('aseba/events/ground', AsebaEvent, self.on_aseba_ground_event)
        rospy.set_param("~ground_threshold", ground_threshold)

        self.imu = Imu(header=rospy.Header(frame_id=self.robot_frame))
        # no orientation or angular velocity information
        self.imu.orientation_covariance[0] = -1
        self.imu.angular_velocity_covariance[0] = -1
        # just an accelerometer
        self.imu.linear_acceleration_covariance[0] = 0.07
        self.imu.linear_acceleration_covariance[4] = 0.07
        self.imu.linear_acceleration_covariance[8] = 0.07

        self.imu_publisher = rospy.Publisher('imu', Imu, queue_size=1)
        rospy.Subscriber('aseba/events/accelerometer',
                         AsebaEvent, self.on_aseba_accelerometer_event)

        self.tap_publisher = rospy.Publisher('tap', Empty, queue_size=1)
        rospy.Subscriber('aseba/events/tap', AsebaEvent, self.on_aseba_tap_event)

        self.temperature = Temperature(
            header=rospy.Header(frame_id=self.robot_frame))
        self.temperature.variance = 0.01
        self.temperature_publisher = rospy.Publisher('temperature', Temperature, queue_size=1)
        rospy.Subscriber('aseba/events/temperature', AsebaEvent, self.on_aseba_temperature_event)

        self.sound_publisher = rospy.Publisher('sound', Float32, queue_size=1)
        self.sound_threshold_publisher = rospy.Publisher(
            'aseba/events/set_sound_threshold', AsebaEvent, queue_size=1)
        rospy.Subscriber('aseba/events/sound', AsebaEvent, self.on_aseba_sound_event)
        rospy.Subscriber('sound_threshold', Float32, self.on_sound_threshold)

        self.remote_publisher = rospy.Publisher('remote', Int8, queue_size=1)
        rospy.Subscriber('aseba/events/remote', AsebaEvent, self.on_aseba_remote_event)

        rospy.Subscriber('comm/transmit', Int16, self.on_sound_threshold)
        self.comm_publisher = rospy.Publisher('comm/receive', Int16, queue_size=1)
        self.aseba_set_comm_publisher = rospy.Publisher(
            'aseba/events/set_comm', AsebaEvent, queue_size=1)
        rospy.Subscriber('aseba/events/comm', AsebaEvent, self.on_aseba_comm_event)

        # actuators

        for name in BODY_LEDS:
            rospy.Subscriber('led/body/' + name, ColorRGBA, self.on_body_led(name))

        rospy.Subscriber('led', Led, self.on_led)
        self.aseba_led_publisher = rospy.Publisher(
            'aseba/events/set_led', AsebaEvent, queue_size=6)

        rospy.Subscriber('led/off', Empty, self.on_led_off)

        rospy.Subscriber('led/gesture', LedGesture, self.on_led_gesture)
        self.aseba_led_gesture_publisher = rospy.Publisher(
            'aseba/events/set_led_gesture', AsebaEvent, queue_size=6)
        rospy.Subscriber('led/gesture/circle', Float32, self.on_led_gesture_circle)
        rospy.Subscriber('led/gesture/off', Empty, self.on_led_gesture_off)
        rospy.Subscriber('led/gesture/blink', Float32, self.on_led_gesture_blink)
        rospy.Subscriber('led/gesture/kit', Float32, self.on_led_gesture_kit)
        rospy.Subscriber('led/gesture/alive', Empty, self.on_led_gesture_alive)

        rospy.Subscriber('sound/play', Sound, self.on_sound_play)
        self.aseba_led_gesture_publisher = rospy.Publisher(
            'aseba/events/set_led_gesture', AsebaEvent, queue_size=6)
        rospy.Subscriber('sound/play/system', SystemSound, self.on_system_sound_play)
        self.aseba_play_sound_publisher = rospy.Publisher(
            'aseba/events/play_sound', AsebaEvent, queue_size=1)
        self.aseba_play_system_sound_publisher = rospy.Publisher(
            'aseba/events/play_system_sound', AsebaEvent, queue_size=1)

        rospy.Subscriber('alarm', Bool, self.on_alarm)
        self.alarm_timer = None

        rospy.Subscriber('shutdown', Empty, self.on_shutdown_msg)
        self.aseba_shutdown_publisher = rospy.Publisher(
            'aseba/events/shutdown', AsebaEvent, queue_size=1)

        rospy.on_shutdown(self.shutdown)

        Server(ThymioConfig, self.change_config)
        # tell ros that we are ready
        rospy.Service('thymio_is_ready', std_srvs.srv.Empty, self.ready)

    def on_shutdown_msg(self, msg):
        self.aseba_shutdown_publisher.publish(
            AsebaEvent(rospy.get_rostime(), 0, []))

    def ready(self, req):
        return std_srvs.srv.Empty()

    def play_system_sound(self, sound):
        self.aseba_play_system_sound_publisher.publish(
            AsebaEvent(rospy.get_rostime(), 0, [sound]))

    def alarm_cb(self, evt):
        self.play_system_sound(2)

    def on_alarm(self, msg):
        if msg.data and not self.alarm_timer:
            self.alarm_timer = rospy.Timer(rospy.Duration(3), self.alarm_cb)
        if not msg.data and self.alarm_timer:
            self.alarm_timer.shutdown()
            self.alarm_timer = None

    def on_sound_play(self, msg):
        freq = max(1, int(msg.frequency))
        duration = max(1, int(msg.duration.to_sec() * 60))
        self.aseba_play_sound_publisher.publish(
            AsebaEvent(rospy.get_rostime(), 0, [freq, duration]))

    def on_system_sound_play(self, msg):
        self.play_system_sound(msg.sound)

    def set_led_gesture(self, gesture, leds, wave, period, length, mirror, mask):
        period = max(-32678, min(32678, int(period * 1000)))
        data = [gesture, leds, wave, period, length, mirror] + mask[:8]
        data += [1] * (14 - len(data))
        self.aseba_led_gesture_publisher.publish(
            AsebaEvent(rospy.get_rostime(), 0, data))

    def on_led_gesture(self, msg):
        self.set_led_gesture(msg.gesture, msg.leds, msg.wave,
                             msg.period, msg.length, msg.mirror, msg.mask)

    def on_led_gesture_off(self, msg):
        self.set_led_gesture(LedGesture.OFF, 0, 0, 0, 0, 0, [])

    def on_led_gesture_circle(self, msg):
        self.set_led_gesture(LedGesture.WAVE, LedGesture.CIRCLE,
                             LedGesture.HARMONIC, msg.data, 8, 0, [])

    def on_led_gesture_blink(self, msg):
        self.set_led_gesture(LedGesture.WAVE, LedGesture.CIRCLE,
                             LedGesture.HARMONIC, msg.data, 1, 0, [])

    def on_led_gesture_kit(self, msg):
        self.set_led_gesture(LedGesture.WAVE, LedGesture.PROXIMITY,
                             LedGesture.HARMONIC, msg.data, 12, 11, [1, 1, 1, 1, 1, 1, 0, 0])

    def on_led_gesture_alive(self, msg):
        self.set_led_gesture(LedGesture.WAVE, LedGesture.CIRCLE,
                             LedGesture.RECT, 3.0, 24, 0, [])

    def on_led_off(self, msg):
        for i in LED_NUMBER.keys():
            self.aseba_led_publisher.publish(
                AsebaEvent(rospy.get_rostime(), 0, [i] + 8 * [0]))
            # sleep to avoid that aseba or ros do not process all messages.
            # could be improved by having 6 separate aseba topics where to send
            # messages
            rospy.sleep(0.005)

    def on_led(self, msg):
        i = msg.id
        num = LED_NUMBER.get(i, 0)
        if num <= len(msg.values):
            data = [i] + [int(32 * v) for v in msg.values[:8]]
            data += [0] * (9 - len(data))
            self.aseba_led_publisher.publish(
                AsebaEvent(rospy.get_rostime(), 0, data))

    def on_body_led(self, name):
        publisher = rospy.Publisher(
            'aseba/events/set_led_' + name, AsebaEvent, queue_size=1)

        def callback(msg):
            r = int(msg.r * 32)
            g = int(msg.g * 32)
            b = int(msg.b * 32)
            aseba_msg = AsebaEvent(rospy.get_rostime(), 0, [r, g, b])
            publisher.publish(aseba_msg)
        return callback

    def on_aseba_comm_event(self, msg):
        self.comm_publisher.publish(Int16(msg.data[0]))

    def on_aseba_remote_event(self, msg):
        self.remote_publisher.publish(Int8(msg.data[1]))

    def on_sound_threshold(self, msg):
        value = msg * 255
        if value < 0:
            value = 1
        if value > 255:
            value = 0
        self.sound_threshold_publisher.publish(
            AsebaEvent(rospy.get_rostime(), 0, [value]))

    def on_aseba_sound_event(self, msg):
        self.sound_publisher.publish(Float32(msg.data[0] / 255.0))

    def on_aseba_tap_event(self, msg):
        self.tap_publisher.publish(Empty())

    def on_aseba_temperature_event(self, msg):
        self.temperature.temperature = msg.data[0] / 10.0
        self.temperature_publisher.publish(self.temperature)

# TODO check how it's implemented in the firmware.

    def on_aseba_accelerometer_event(self, msg):
        self.imu.linear_acceleration.x = msg.data[1] / 23.0 * 9.81
        self.imu.linear_acceleration.y = -msg.data[0] / 23.0 * 9.81
        self.imu.linear_acceleration.z = msg.data[2] / 23.0 * 9.81
        self.imu.header.stamp = rospy.Time.now()
        self.imu_publisher.publish(self.imu)

    def on_aseba_ground_event(self, msg):
        data = msg.data
        ir_threshold = rospy.get_param("~ground_threshold", 200)

        for sensor, value in zip(self.ground_sensors, data):
            sensor['msg'].range = float('inf') if (
                value < ir_threshold) else -float('inf')
            sensor['msg'].header.stamp = rospy.Time.now()
            sensor['publisher'].publish(sensor['msg'])

    # basics logarithmic fit
    @staticmethod
    def proximity2range(raw):
        if raw > 4000:
            return -float('inf')
        if raw < 800:
            return float('inf')
        return -0.0736 * log(raw) + 0.632

    def on_aseba_proximity_event(self, msg):
        data = msg.data
        values = [self.proximity2range(d) for d in data]
        for sensor, value in zip(self.proximity_sensors, values):
            sensor['msg'].range = value
            sensor['msg'].header.stamp = rospy.Time.now()
            sensor['publisher'].publish(sensor['msg'])

        self.proximityToLaser.ranges = []
        self.proximityToLaser.intensities = []
        self.proximityToLaser.header.stamp = rospy.Time.now()
        for dist, raw in zip(values, data)[4::-1]:
            if dist > 0.14:
                dist = 0.14
            if dist < 0.0215:
                dist = 0.0215
            self.proximityToLaser.ranges.append(dist + 0.08)
            self.proximityToLaser.intensities.append(raw)
        self.proximityToLaserPublisher.publish(self.proximityToLaser)

    def on_aseba_button_event(self, button):
        publisher = rospy.Publisher('buttons/' + button, Bool, queue_size=1)

        def callback(msg):
            bool_msg = Bool(msg.data[0])
            publisher.publish(bool_msg)
        return callback

    # ======== we send the speed to the aseba running on the robot  ========
    def set_speed(self, values):
        self.aseba_pub.publish(AsebaEvent(rospy.get_rostime(), 0, values))

    # ======== stop the robot safely ========
    def shutdown(self):
        self.set_speed([0, 0])

    def on_aseba_buttons_event(self, data):
        self.buttons.header.stamp = rospy.Time.now()
        self.buttons.buttons = data.data
        self.buttons_pub.publish(self.buttons)

    # ======== processing odometry events received from the robot ========
    def on_aseba_odometry_event(self, data):
        now = data.stamp
        dt = (now - self.then).to_sec()
        self.then = now

        m_l, m_r = data.data
        if abs(m_l) < self.motor_speed_deadband:
            m_l = 0
        if abs(m_r) < self.motor_speed_deadband:
            m_r = 0

        vl = self.left_wheel_speed(m_l)
        vr = self.right_wheel_speed(m_r)

        # wheel joint states
        left_wheel_angular_speed = vl / WHEEL_RADIUS
        right_wheel_angular_speed = vr / WHEEL_RADIUS

        self.left_wheel_angle += dt * left_wheel_angular_speed
        self.right_wheel_angle += dt * right_wheel_angular_speed

        dsl = vl * dt  # left wheel delta in m
        dsr = vr * dt  # right wheel delta in m

        # robot traveled distance in meters
        ds = ((dsl + dsr) / 2.0)
        dth = (dsr - dsl) / self.axis  # turn angle

        self.x += ds * cos(self.th + dth / 2.0)
        self.y += ds * sin(self.th + dth / 2.0)
        self.th += dth

        # We publish odometry, tf, and wheel joint state only at a maximal rate:
        if self.odom_min_period > (now - self.odom_msg.header.stamp).to_sec():
            return

        self.wheel_state_msg.header.stamp = rospy.Time.now()
        self.wheel_state_msg.position = [self.left_wheel_angle, self.right_wheel_angle]
        self.wheel_state_msg.velocity = [left_wheel_angular_speed, right_wheel_angular_speed]
        self.wheel_state_pub.publish(self.wheel_state_msg)

        # prepare tf from base_link to odom
        quaternion = Quaternion()
        quaternion.z = sin(self.th / 2.0)
        quaternion.w = cos(self.th / 2.0)

        # prepare odometry
        self.odom_msg.header.stamp = rospy.Time.now()  # OR TO TAKE ONE FROM THE EVENT?
        self.odom_msg.pose.pose.position.x = self.x
        self.odom_msg.pose.pose.position.y = self.y
        self.odom_msg.pose.pose.orientation = quaternion

        if(dt > 0):
            self.odom_msg.twist.twist.linear.x = ds / dt
            self.odom_msg.twist.twist.angular.z = dth / dt

        # publish odometry
        self.odom_broadcaster.sendTransform(
            (self.x, self.y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            self.then, self.robot_frame, self.odom_frame)
        self.odom_pub.publish(self.odom_msg)

    def set_linear_angular_speed(self, speed, ang_speed):
        left_wheel_speed = speed - ang_speed * 0.5 * self.axis
        right_wheel_speed = speed + ang_speed * 0.5 * self.axis

        left_motor_speed = round(self.left_wheel_motor_speed(left_wheel_speed))
        right_motor_speed = round(self.right_wheel_motor_speed(right_wheel_speed))
        max_motor_speed = max(abs(left_motor_speed), abs(right_motor_speed))
        if max_motor_speed > MAX_SPEED:
            return self.set_linear_angular_speed(speed * MAX_SPEED / max_motor_speed,
                                                 ang_speed * MAX_SPEED / max_motor_speed)

        self.set_speed([left_motor_speed, right_motor_speed])

    def on_cmd_vel(self, data):
        self.set_linear_angular_speed(data.linear.x, data.angular.z)
Ejemplo n.º 20
0
class NeatoNode:
	
    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        self.CMD_RATE =2 

        self.port = rospy.get_param('~port', "/dev/ttyUSB0")
        rospy.loginfo("Using port: %s" % self.port)

        self.robot = Botvac(self.port)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('base_scan', LaserScan, queue_size=10)
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.buttonPub = rospy.Publisher('button', Button, queue_size=10)
        self.sensorPub = rospy.Publisher('sensor', Sensor, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        self.cmd_vel = [0, 0]
        self.old_vel = self.cmd_vel

    def spin(self):
        encoders = [0, 0]

        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0
        then = rospy.Time.now()

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id', 'base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link))

        scan.angle_min =0.0 
        scan.angle_max =359.0*pi/180.0 
        scan.angle_increment =pi/180.0 
        scan.range_min = 0.020
        scan.range_max = 5.0

        odom = Odometry(header=rospy.Header(frame_id="odom"), child_frame_id='base_footprint')

        button = Button()
        sensor = Sensor()
        self.robot.setBacklight(1)
        self.robot.setLED("Green")
        # main loop of driver
        r = rospy.Rate(20)
        cmd_rate= self.CMD_RATE

        while not rospy.is_shutdown():
            # notify if low batt
            #if self.robot.getCharger() < 10:
            #    print "battery low " + str(self.robot.getCharger()) + "%"
            # get motor encoder values
            left, right = self.robot.getMotors()

            cmd_rate = cmd_rate-1
            if cmd_rate ==0:
		    # send updated movement commands
		    #if self.cmd_vel != self.old_vel or self.cmd_vel == [0,0]:
                    # max(abs(self.cmd_vel[0]),abs(self.cmd_vel[1])))
		    #self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1], (abs(self.cmd_vel[0])+abs(self.cmd_vel[1]))/2)
		    self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1], max(abs(self.cmd_vel[0]),abs(self.cmd_vel[1])))
		    cmd_rate = self.CMD_RATE

            self.old_vel = self.cmd_vel

            # prepare laser scan
            scan.header.stamp = rospy.Time.now()
           
            self.robot.requestScan()
            scan.ranges = self.robot.getScanRanges()

            # now update position information
            dt = (scan.header.stamp - then).to_sec()
            then = scan.header.stamp

            d_left =  (left - encoders[0])/1000.0
            d_right =  (right - encoders[1])/1000.0
            encoders = [left, right]

	    #print d_left, d_right, encoders

            dx = (d_left+d_right)/2
            dth = (d_right-d_left)/(self.robot.base_width/1000.0)

            x = cos(dth)*dx
            y = -sin(dth)*dx
            self.x += cos(self.th)*x - sin(self.th)*y
            self.y += sin(self.th)*x + cos(self.th)*y
            self.th += dth
            #print self.x,self.y,self.th

            # prepare tf from base_link to odom
            quaternion = Quaternion()
            quaternion.z = sin(self.th/2.0)
            quaternion.w = cos(self.th/2.0)

            # prepare odometry
            odom.header.stamp = rospy.Time.now()
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = dx/dt
            odom.twist.twist.angular.z = dth/dt


            # sensors
            lsb, rsb, lfb, rfb = self.robot.getDigitalSensors()

            # buttons
            btn_soft, btn_scr_up, btn_start, btn_back, btn_scr_down = self.robot.getButtons()


            # publish everything
            self.odomBroadcaster.sendTransform((self.x, self.y, 0), (quaternion.x, quaternion.y, quaternion.z,
                                                                     quaternion.w), then, "base_footprint", "odom")
            self.scanPub.publish(scan)
            self.odomPub.publish(odom)
            button_enum = ("Soft_Button", "Up_Button", "Start_Button", "Back_Button", "Down_Button")
            sensor_enum = ("Left_Side_Bumper", "Right_Side_Bumper", "Left_Bumper", "Right_Bumper")
            for idx, b in enumerate((btn_soft, btn_scr_up, btn_start, btn_back, btn_scr_down)):
                if b == 1:
                    button.value = b
                    button.name = button_enum[idx]
                    self.buttonPub.publish(button)

            for idx, b in enumerate((lsb, rsb, lfb, rfb)):
                if b == 1:
                    sensor.value = b
                    sensor.name = sensor_enum[idx]
                    self.sensorPub.publish(sensor)
            # wait, then do it again
            r.sleep()

        # shut down
        self.robot.setBacklight(0)
        self.robot.setLED("Off")
        self.robot.setLDS("off")
        self.robot.setTestMode("off")

    def sign(self,a):
        if a>=0:
		return 1
	else:
		return-1

    def cmdVelCb(self,req):
        x = req.linear.x * 1000
        th = req.angular.z * (self.robot.base_width/2)
        k = max(abs(x-th),abs(x+th))
        # sending commands higher than max speed will fail

        if k > self.robot.max_speed:
            x = x*self.robot.max_speed/k; th = th*self.robot.max_speed/k

        self.cmd_vel = [int(x-th), int(x+th)]
Ejemplo n.º 21
0
class SMALdogROS:

    def __init__(self, execute=False):
        self.robot = SMALdog()
        if execute:
            self.conn = EthBridge()
        else:
            self.conn = None

        self.x = 0
        self.y = 0

        self.joint_state_pub = rospy.Publisher('joint_states', JointState)
        self.odom_broadcaster = TransformBroadcaster()
        rospy.Subscriber("cmd_vel", Twist, self.cmdCb)
    
    def run(self):
        controller = MuybridgeGaitController(self.robot, self.robot.DEFAULT_STANCE)
        old_pose = self.robot.getIK(self.robot.DEFAULT_STANCE)
        old_pose["x"] = 0.0
        old_pose["y"] = 0.0
        old_pose["r"] = 0.0

        draw = StabilityVisualization(self.robot)

        r = rospy.Rate(50)
        while not rospy.is_shutdown():
            # get stance from controller TODO: this really should be a motion plan
            new_stance = controller.next(self.x, 0, 0) # TODO: add y/r
            t = new_stance[0]
            #draw.draw(new_stance[1], controller)

            # do IK
            new_pose = self.robot.getIK(new_stance[1])
            new_pose["x"] = controller.x
            new_pose["y"] = controller.y
            new_pose["r"] = controller.r

            # interpolate
            for pose in self.interpolate(old_pose, new_pose, int(t/0.02)):
                # publish
                msg = JointState()
                msg.header.stamp = rospy.Time.now()
                for name in self.robot.names:
                    msg.name.append(name)
                    msg.position.append(pose[name])
                    if pose[name] == float('nan'):
                        print "WARN", name, "is nan"
                self.joint_state_pub.publish(msg)

                # TF
                quaternion = Quaternion()
                quaternion.x = 0.0
                quaternion.y = 0.0
                quaternion.z = sin(pose["r"]/2)
                quaternion.w = cos(pose["r"]/2)
                self.odom_broadcaster.sendTransform(
                    (pose["x"], pose["y"], 0.095),
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(),
                    "body_link",
                    "world"
                    )

                if self.conn:
                    packet = makeSyncWritePacket(convertToAX12(pose, self.robot))
                    self.conn.send(self.conn.makePacket(254, ax12.AX_SYNC_WRITE, packet))

                r.sleep()

            old_pose = new_pose

    def interpolate(self, start_pose, end_pose, iterations):
        diffs = dict()
        for name in start_pose.keys():
            diffs[name] = (end_pose[name] - start_pose[name])/iterations
        for i in range(iterations):
            pose = dict()
            for name in start_pose.keys():
                pose[name] = start_pose[name] + (diffs[name]*i)
            yield pose

    def cmdCb(self, msg):
        # TODO: add y/r
        if msg.linear.x > 0.075:
            self.x = 0.075
        else:
            self.x = msg.linear.x
Ejemplo n.º 22
0
class ThymioDriver():
	# ======== class initialization ======== 
	def __init__(self):
		rospy.init_node('thymio')
		# initialize parameters
		self.x = 0
		self.y = 0
		self.th = 0
		self.then = rospy.Time.now()
		self.odom = Odometry(header=rospy.Header(frame_id='odom'),child_frame_id='base_link')



		# load script on the Thymio
		rospy.wait_for_service('aseba/load_script')


		load_script = rospy.ServiceProxy('aseba/load_script',LoadScripts)
		script_filename = roslib.packages.get_pkg_dir('thymio_driver') + '/aseba/thymio_ros.aesl'
		load_script(script_filename)
		

		# subscribe to topics

		self.aseba_pub = rospy.Publisher('aseba/events/set_speed', AsebaEvent,queue_size=1)
		self.odom_pub = rospy.Publisher('odom',Odometry,queue_size=1)
		self.odom_broadcaster = TransformBroadcaster()
		rospy.Subscriber('aseba/events/odometry', AsebaEvent, self.on_aseba_odometry_event)
		rospy.Subscriber("cmd_vel", Twist, self.on_cmd_vel)



                self.buttons=Joy()
                self.buttons_pub=rospy.Publisher('buttons',Joy,queue_size=1)
                rospy.Subscriber("aseba/events/buttons",AsebaEvent,self.on_aseba_buttons_event)	


                
                
                for button in BUTTONS:
                        rospy.Subscriber('aseba/events/button_'+button,AsebaEvent,self.on_aseba_button_event(button))
        


                self.proximity_sensors=[{
                        'publisher':rospy.Publisher('proximity/'+name,Range,queue_size=1),
                        'msg':Range(header=rospy.Header(frame_id='proximity_'+name+"_link"),radiation_type=Range.INFRARED,field_of_view=0.3,min_range=0.0215,max_range=0.14)
                } for name in PROXIMITY_NAMES]

                self.proximityToLaserPublisher=rospy.Publisher('proximity/laser',LaserScan,queue_size=1)
                self.proximityToLaser=LaserScan(header=rospy.Header(frame_id="base_link"),angle_min=-0.64,angle_max=0.64,angle_increment=0.32,time_increment=0,scan_time=0,range_min=0.0215+0.08,range_max=0.14+0.08)
                rospy.Subscriber('aseba/events/proximity',AsebaEvent,self.on_aseba_proximity_event)        


                self.ground_sensors=[{
                        'publisher':rospy.Publisher('ground/'+name,Range,queue_size=1),
                        'msg':Range(header=rospy.Header(frame_id='ground_'+name+"_link"),radiation_type=Range.INFRARED,field_of_view=0.3,min_range=0.008,max_range=0.008)
                } for name in GROUND_NAMES]

                rospy.Subscriber('aseba/events/ground',AsebaEvent,self.on_aseba_ground_event)      
                rospy.set_param("~ground_threshold",200)
                


                self.imu=Imu(header=rospy.Header(frame_id='base_link'))
                # no orientation or angular velocity information
                self.imu.orientation_covariance[0]=-1
                self.imu.angular_velocity_covariance[0]=-1
                # just an accelerometer
                self.imu.linear_acceleration_covariance[0]=0.07
                self.imu.linear_acceleration_covariance[4]=0.07
                self.imu.linear_acceleration_covariance[8]=0.07

                self.imu_publisher=rospy.Publisher('imu',Imu,queue_size=1)
                rospy.Subscriber('aseba/events/accelerometer',AsebaEvent,self.on_aseba_accelerometer_event)


                self.tap_publisher=rospy.Publisher('tap',Empty,queue_size=1)
                rospy.Subscriber('aseba/events/tap',AsebaEvent,self.on_aseba_tap_event)


                self.temperature=Temperature(header=rospy.Header(frame_id='base_link'))
                self.temperature.variance=0.01
                self.temperature_publisher=rospy.Publisher('temperature',Temperature,queue_size=1)
                rospy.Subscriber('aseba/events/temperature',AsebaEvent,self.on_aseba_temperature_event)


                self.sound_publisher=rospy.Publisher('sound',Float32,queue_size=1)
                self.sound_threshold_publisher = rospy.Publisher('aseba/events/set_sound_threshold', AsebaEvent,queue_size=1)
                rospy.Subscriber('aseba/events/sound',AsebaEvent,self.on_aseba_sound_event)
                rospy.Subscriber('sound_threshold',Float32,self.on_sound_threshold)
                

                self.remote_publisher=rospy.Publisher('remote',Int8,queue_size=1)
                rospy.Subscriber('aseba/events/remote',AsebaEvent,self.on_aseba_remote_event)
                       

                rospy.Subscriber('comm/transmit',Int16,self.on_sound_threshold)
                self.comm_publisher=rospy.Publisher('comm/receive',Int16,queue_size=1)
                self.aseba_set_comm_publisher = rospy.Publisher('aseba/events/set_comm', AsebaEvent,queue_size=1)
                rospy.Subscriber('aseba/events/comm',AsebaEvent,self.on_aseba_comm_event)
                
                #actuators

                for name in BODY_LEDS:
                        rospy.Subscriber('led/body/'+name,ColorRGBA,self.on_body_led(name))


                rospy.Subscriber('led',Led,self.on_led)
                self.aseba_led_publisher=rospy.Publisher('aseba/events/set_led', AsebaEvent,queue_size=6)

                rospy.Subscriber('led/off',Empty,self.on_led_off)

                rospy.Subscriber('led/gesture',LedGesture,self.on_led_gesture)
                self.aseba_led_gesture_publisher=rospy.Publisher('aseba/events/set_led_gesture', AsebaEvent,queue_size=6)
                rospy.Subscriber('led/gesture/circle',Float32,self.on_led_gesture_circle)
                rospy.Subscriber('led/gesture/off',Empty,self.on_led_gesture_off)
                rospy.Subscriber('led/gesture/blink',Float32,self.on_led_gesture_blink)
                rospy.Subscriber('led/gesture/kit',Float32,self.on_led_gesture_kit)
                rospy.Subscriber('led/gesture/alive',Empty,self.on_led_gesture_alive)
               
                rospy.Subscriber('sound/play',Sound,self.on_sound_play)
                self.aseba_led_gesture_publisher=rospy.Publisher('aseba/events/set_led_gesture', AsebaEvent,queue_size=6)
                rospy.Subscriber('sound/play/system',SystemSound,self.on_system_sound_play)
                self.aseba_play_sound_publisher=rospy.Publisher('aseba/events/play_sound', AsebaEvent,queue_size=1)
                self.aseba_play_system_sound_publisher=rospy.Publisher('aseba/events/play_system_sound', AsebaEvent,queue_size=1)

                rospy.Subscriber('alarm',Bool,self.on_alarm)
                self.alarm_timer=None



                rospy.Subscriber('shutdown',Empty,self.on_shutdown_msg)
                self.aseba_shutdown_publisher=rospy.Publisher('aseba/events/shutdown', AsebaEvent,queue_size=1)

                #tell ros that we are ready
                rospy.Service('thymio_is_ready',std_srvs.srv.Empty, self.ready)


        def on_shutdown_msg(self,msg):
                self.aseba_shutdown_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[]))


        def ready(self,req):
                return std_srvs.srv.Empty()




        def play_system_sound(self,sound):
                self.aseba_play_system_sound_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[sound]))

        def alarm_cb(self,evt):
                self.play_system_sound(2)

        def on_alarm(self,msg):
                if msg.data and not self.alarm_timer:
                        self.alarm_timer=rospy.Timer(rospy.Duration(3),self.alarm_cb)
                if msg.data==False and self.alarm_timer:
                        self.alarm_timer.shutdown()
                        self.alarm_timer=None
                



        def on_sound_play(self,msg):
                freq=max(1,int(msg.frequency))
                duration=max(1,int(msg.duration.to_sec()*60))
                self.aseba_play_sound_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[freq,duration]))

        def on_system_sound_play(self,msg):
                self.play_system_sound(msg.sound)

        



        def set_led_gesture(self,gesture,leds,wave,period,length,mirror,mask):
                period=max(-32678,min(32678,int(period*1000)))
                data=[gesture,leds,wave,period,length,mirror]+mask[:8]
                data+=[1]*(14-len(data))
                self.aseba_led_gesture_publisher.publish(AsebaEvent(rospy.get_rostime(),0,data))

 
        def on_led_gesture(self,msg):
                self.set_led_gesture(msg.gesture,msg.leds,msg.wave,msg.period,msg.length,msg.mirror,msg.mask)

        def on_led_gesture_off(self,msg):
                self.set_led_gesture(LedGesture.OFF,0,0,0,0,0,[])
                
        def on_led_gesture_circle(self,msg):
                self.set_led_gesture(LedGesture.WAVE,LedGesture.CIRCLE,LedGesture.HARMONIC,msg.data,8,0,[])

        def on_led_gesture_blink(self,msg):
                self.set_led_gesture(LedGesture.WAVE,LedGesture.CIRCLE,LedGesture.HARMONIC,msg.data,1,0,[])               
        def on_led_gesture_kit(self,msg):
                self.set_led_gesture(LedGesture.WAVE,LedGesture.PROXIMITY,LedGesture.HARMONIC,msg.data,12,11,[1,1,1,1,1,1,0,0])                      

        def on_led_gesture_alive(self,msg):
                self.set_led_gesture(LedGesture.WAVE,LedGesture.CIRCLE,LedGesture.RECT,3.0,24,0,[])

        def on_led_off(self,msg):
                for i in LED_NUMBER.keys():
                        print 'off ',i
                        self.aseba_led_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[i]+8*[0]))
                        # sleep to avoid that aseba or ros do not process all messages.
                        # could be improved by having 6 separate aseba topics where to send messages
                        rospy.sleep(0.005)

        def on_led(self,msg):
                i=msg.id
                num=LED_NUMBER.get(i,0)
                if num<=len(msg.values):
                        data=[i]+[int(32*v) for v in msg.values[:8]]
                        data+=[0]*(9-len(data))
                        self.aseba_led_publisher.publish(AsebaEvent(rospy.get_rostime(),0,data))

           
        def on_body_led(self,name):
                publisher=rospy.Publisher('aseba/events/set_led_'+name,AsebaEvent,queue_size=1)
                def callback(msg):
                        r=int(msg.r*32)
                        g=int(msg.g*32)
                        b=int(msg.b*32)
                        aseba_msg=AsebaEvent(rospy.get_rostime(),0,[r,g,b])
                        publisher.publish(aseba_msg)
                return callback             


        def on_set_comm(self,msg):
                self.aseba_set_comm_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[enabled,payload]))

        def on_aseba_comm_event(self,msg):
                self.comm_publisher.publish(Int16(msg.data[0]))
        
        def on_aseba_remote_event(self,msg):
                self.remote_publisher.publish(Int8(msg.data[1]))
        
        

        def on_sound_threshold(self,msg):
                value=msg*255
                if value<0:
                        value=1
                if value>255:
                        value=0
                self.sound_threshold_publisher.publish(AsebaEvent(rospy.get_rostime(),0,[value]))

        def on_aseba_sound_event(self,msg):
                self.sound_publisher.publish(Float32(msg.data[0]/255.0))
        

        def on_aseba_tap_event(self,msg):
                self.tap_publisher.publish(Empty())


        def on_aseba_temperature_event(self,msg):
                self.temperature.temperature=msg.data[0]/10.0
                self.temperature_publisher.publish(self.temperature)
        


#TODO check how it's implemented in the firmware.

        def on_aseba_accelerometer_event(self,msg):
                self.imu.linear_acceleration.x=msg.data[1]/23.0*9.81
                self.imu.linear_acceleration.y=-msg.data[0]/23.0*9.81
                self.imu.linear_acceleration.z=msg.data[2]/23.0*9.81
                self.imu.header.stamp=rospy.Time.now()
                self.imu_publisher.publish(self.imu)

        def on_aseba_ground_event(self,msg):
                data=msg.data
                ir_threshold=rospy.get_param("~ground_threshold",200)
                
                for sensor,value  in zip(self.ground_sensors,data):
                        sensor['msg'].range=float('inf') if (value<ir_threshold) else -float('inf')
                        sensor['msg'].header.stamp=rospy.Time.now()
                        sensor['publisher'].publish(sensor['msg'])
                
        

        # basics logarithmic fit
        @staticmethod
        def proximity2range(raw):
                if raw>4000:
                        return -float('inf')
                if raw<800:
                        return float('inf')
                return -0.0736*log(raw)+0.632 
        
        def on_aseba_proximity_event(self,msg):
                data=msg.data
                values=[self.proximity2range(d) for d in data]
                for sensor,value  in zip(self.proximity_sensors,values):
                        sensor['msg'].range=value
                        sensor['msg'].header.stamp=rospy.Time.now()
                        sensor['publisher'].publish(sensor['msg'])

                self.proximityToLaser.ranges=[]
                self.proximityToLaser.intensities=[]
                self.proximityToLaser.header.stamp=rospy.Time.now()
                for dist,raw in zip(values,data)[4::-1]:
                        if dist>0.14:
                                dist=0.14
                        if dist<0.0215:
                                dist=0.0215
                        self.proximityToLaser.ranges.append(dist+0.08)
                        self.proximityToLaser.intensities.append(raw)
                    
                        
                self.proximityToLaserPublisher.publish(self.proximityToLaser)
                

        def on_aseba_button_event(self,button):
                publisher=rospy.Publisher('buttons/'+button,Bool,queue_size=1)
                def callback(msg):
                        bool_msg=Bool(msg.data[0])
                        publisher.publish(bool_msg)
                return callback

	# ======== we send the speed to the aseba running on the robot  ======== 
	def set_speed(self,values):
		self.aseba_pub.publish(AsebaEvent(rospy.get_rostime(),0,values))
	
	# ======== stop the robot safely ======== 
	def shutdown(self):
		self.set_speed([0,0])
                

        def on_aseba_buttons_event(self,data):
                self.buttons.header.stamp=rospy.Time.now()
                self.buttons.buttons=data.data
                self.buttons_pub.publish(self.buttons)

	# ======== processing odometry events received from the robot ======== 
	def on_aseba_odometry_event(self,data): 
		now = data.stamp
		dt = (now-self.then).to_sec()
		self.then = now
		dsl = (data.data[0]*dt)/SPEED_COEF # left wheel delta in mm
		dsr = (data.data[1]*dt)/SPEED_COEF # right wheel delta in mm
		ds = ((dsl+dsr)/2.0)/1000.0      # robot traveled distance in meters
		dth = (dsr-dsl)/BASE_WIDTH  # turn angle

		self.x += ds*cos(self.th+dth/2.0)
		self.y += ds*sin(self.th+dth/2.0)
		self.th+= dth

		# prepare tf from base_link to odom 
		quaternion = Quaternion()
		quaternion.z = sin(self.th/2.0)
		quaternion.w = cos(self.th/2.0)

		# prepare odometry
		self.odom.header.stamp = rospy.Time.now() # OR TO TAKE ONE FROM THE EVENT?
		self.odom.pose.pose.position.x = self.x
		self.odom.pose.pose.position.y = self.y
		self.odom.pose.pose.position.z = 0
		self.odom.pose.pose.orientation = quaternion

                if(dt>0):
                        self.odom.twist.twist.linear.x = ds/dt
                        self.odom.twist.twist.angular.z = dth/dt

		# publish odometry
		self.odom_broadcaster.sendTransform((self.x,self.y,0),(quaternion.x,quaternion.y,quaternion.z,quaternion.w),self.then,"base_link","odom")
		self.odom_pub.publish(self.odom)
	
	# ======== processing events received from the robot  ======== 
	def on_cmd_vel(self,data):
		x = data.linear.x * 1000.0 # from meters to millimeters 
		x = x * SPEED_COEF # to thymio units
		th = data.angular.z * (BASE_WIDTH/2) # in mm
		th = th * SPEED_COEF # in thymio units
		k = max(abs(x-th),abs(x+th))
		# sending commands higher than max speed will fail
		if k > MAX_SPEED:
			x = x*MAX_SPEED/k; th = th*MAX_SPEED/k
		self.set_speed([int(x-th),int(x+th)])

	# ======== ======== ======== ======== ======== ======== ========      
	def control_loop(self):	
		rospy.on_shutdown(self.shutdown) # on shutdown hook
		while not rospy.is_shutdown():
			rospy.spin()
class DiffTf:
#############################################################################

    #############################################################################
    def __init__(self):
    #############################################################################
        rospy.init_node("diff_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)
        
        #### parameters #######

	#Wheel radius : 0.0325 
        # wheel circum = 2* 3.14 * 0.0325 = 0.2041
	# One rotation encoder ticks : 8 ticks
	# For 1 meter: 8 * ( 1 / 0.2041) = 39 ticks

        self.rate = rospy.get_param('~rate',10.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param('ticks_meter', 39))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param('~base_width', 0.125)) # The wheel base width in meters
        
        self.base_frame_id = rospy.get_param('~base_frame_id','base_footprint') # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param('~odom_frame_id', 'odom') # the name of the odometry reference frame
        
        self.encoder_min = rospy.get_param('encoder_min', -2147483648)
        self.encoder_max = rospy.get_param('encoder_max', 2147483648)
        self.encoder_low_wrap = rospy.get_param('wheel_low_wrap', (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min )
        self.encoder_high_wrap = rospy.get_param('wheel_high_wrap', (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min )
 
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = rospy.Time.now() + self.t_delta
        
        # internal data
        self.enc_left = None        # wheel encoder readings
        self.enc_right = None
        self.left = 0               # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0                  # position in xy plane 
        self.y = 0
        self.th = 0
        self.dx = 0                 # speeds in x/rotation
        self.dr = 0

	self.yaw = 0.01
	self.pitch = 0.01
	self.roll = 0.01

        self.then = rospy.Time.now()

        self.quaternion_1 = Quaternion()
        
        # subscriptions
        rospy.Subscriber("left_ticks", Int32, self.lwheelCallback)
        rospy.Subscriber("right_ticks", Int32, self.rwheelCallback)

        #rospy.Subscriber("imu_data", Vector3, self.imu_value_update)


        self.odomPub = rospy.Publisher("odom", Odometry,queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        
    #############################################################################
    def spin(self):
    #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()
       
     
    #############################################################################
    def update(self):
    #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()
            

            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right
           
            # distance traveled is the average of the two wheels 
            d = ( d_left + d_right ) / 2
            # this approximation works (in radians) for small angles
            th = ( d_right - d_left ) / self.base_width
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed
           

             
            if (d != 0):
                # calculate distance traveled in x and y
                x = cos( th ) * d
                y = -sin( th ) * d
                # calculate the final position of the robot
                self.x = self.x + ( cos( self.th ) * x - sin( self.th ) * y )
                self.y = self.y + ( sin( self.th ) * x + cos( self.th ) * y )
            if( th != 0):
                self.th = self.th + th
                
            # publish the odom information
            quaternion = Quaternion()


            quaternion.x = 0.0
            quaternion.y = 0.0

            quaternion.z = sin( self.th / 2 )
            quaternion.w = cos( self.th / 2 )

	    '''
            try:		
            	quaternion.z = self.quaternion_1[2]
            	quaternion.w = self.quaternion_1[3]

	    except:
		quaternion.z = sin( self.th / 2 )
		quaternion.w = cos( self.th / 2 )
		pass
            '''
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )
            
            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)
            
    def imu_value_update(self, imu_data):
	    orient = Vector3()

            orient = imu_data

	    self.yaw = orient.x
 	    self.pitch = orient.y
	    self.roll = orient.z

	    try:	
	    	self.quaternion_1 = tf.transformations.quaternion_from_euler(self.yaw, self.pitch, self.roll)
	  	#print self.quaternion_1[0]
	  	#print self.quaternion_1[1]
	  	#print self.quaternion_1[2]
	  	#print self.quaternion_1[3]

 	    except:
		rospy.logwarn("Unable to get quaternion values")
	        pass


    #############################################################################
    def lwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1
            
        if (enc > self.encoder_high_wrap and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1
            
        self.left = 1.0 * (enc + self.lmult * (self.encoder_max - self.encoder_min)) 


        self.prev_lencoder = enc
        
    #############################################################################
    def rwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if(enc < self.encoder_low_wrap and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1
        
        if(enc > self.encoder_high_wrap and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1
            
        self.right = 1.0 * (enc + self.rmult * (self.encoder_max - self.encoder_min))


        self.prev_rencoder = enc
Ejemplo n.º 24
0
class odom():
    def __init__(self):
        self.sub = rospy.Subscriber('/encoders', encoders, self.my_callback)
        self.pub = rospy.Publisher('/odom', Odometry, queue_size=1)
        self.odo = Odometry()
        self.read = encoders()
        self.Fistleftenco_tick = 0
        self.Firstrightenco_tick = 0
        rospy.sleep(0.5)
        self.R = 0.1
        self.L = 0.3
        self.N = 360
        self.x = 0
        self.y = 0
        self.odom_broadcaster = TransformBroadcaster()
        self.theta = 0.0
        self.last_time = rospy.Time.now()

    def my_callback(self, msg):
        self.read = msg
        self.Lastleftenco_tick = self.read.encoderTicks[0]
        self.Lastrightenco_tick = self.read.encoderTicks[1]

    def readings(self):
        while not rospy.is_shutdown():
            present_time = rospy.Time.now()
            Dr = 2 * pi * self.R * (self.Fistleftenco_tick -
                                    self.Lastleftenco_tick) / self.N
            Dl = 2 * pi * self.R * (self.Firstrightenco_tick -
                                    self.Lastrightenco_tick) / self.N

            self.Firstrightenco_tick = self.Lastrightenco_tick
            self.Fistleftenco_tick = self.Lastleftenco_tick

            v = (Dr + Dl) / 2
            w = (Dr - Dl) / self.L

            self.x += v * cos(self.theta)
            self.y += v * sin(self.theta)
            self.theta += w

            #get the quaternion created from yaw
            odom_quat = tf.transformations.quaternion_from_euler(
                0, 0, self.theta)

            self.odom_broadcaster.sendTransform(
                (self.x, self.y, 0.), odom_quat, present_time, "link_chassis",
                "odom")

            self.odo.header.stamp = present_time
            self.odo.header.frame_id = "odom"

            self.odo.pose.pose = Pose(Point(self.x, self.y, 0.),
                                      Quaternion(*odom_quat))

            self.odo.child_frame_id = "link_chassis"
            self.odo.twist.twist = Twist(Vector3(v, 0, 0), Vector3(0, 0, w))

            self.pub.publish(self.odo)

            self.last_time = present_time
            rospy.sleep(0.1)
Ejemplo n.º 25
0
class NeatoDriver:
    def __init__(self):
        self.neato = xv11()
        self.sensorPub = rospy.Publisher('neatoSensors', NeatoSensors) # see NOTE above
        self.rangePub  = rospy.Publisher('laserRangeData',LaserRangeData)
        self.fields = self.neato.state.keys() # gets all of the sensors fields from the Neato
        self.neato.update = self.sense
        # for gmapping
        self.odomBroadcaster = TransformBroadcaster()
        # for odometry testing
        self.prevL = 0
        self.prevR = 0
        self.x     = 0
        self.y     = 0
        self.theta = 0
        self.odom = NeatoOdom()
        self.odomPub = rospy.Publisher('neatoOdom', NeatoOdom)
        
    def start(self):
        self.neato.start()
        
    def stop(self, req):
        self.neato.stop()
        return StopResponse(True)

    def tank(self, req):
        self.neato.tank(req.left,req.right)
        return TankResponse(True)

    def playSound(self, req):
        """ plays a sound from the Neato's database.
            num goes from 0 to 20 inclusive
        """
        self.neato.playSound(req.num)
        return PlaySoundResponse(True)

    def sense(self):
        """ collects sensor data from the Neato and publishes
            it to the neatoSensors topic
        """
        # receive and publish sensor data
        self.fields = self.neato.state.keys() # update sensor fields
        sensor_data  = NeatoSensors() # see NOTE above
        for field in self.fields:
            try:
                sensor_data.__setattr__(field, self.neato.state[field])
            except:
                pass
        self.sensorPub.publish(sensor_data)

        # receive and publish laser range data
        range_data = LaserRangeData()
        range_data.__setattr__("range_data", self.neato.range_data)
        self.rangePub.publish(range_data)

        # odomemtry in testing
        self.odomUpdate()
        
        # transform position into tf frame
        quaternionOdom = Quaternion()
        quaternionOdom.x = 0.0
        quaternionOdom.y = 0.0
        quaternionOdom.z = sin(self.theta/2)
        quaternionOdom.w = -cos(self.theta/2)

        quaternionLL = Quaternion()
        quaternionLL.x = 0.0
        quaternionLL.y = 0.0
        quaternionLL.z = 0.0
        quaternionLL.w = 1.0



        
        # base_link -> base_laser transformation
        self.odomBroadcaster.sendTransform(
            (0.0, -0.1, 0.0),
            (quaternionLL.x, quaternionLL.y, quaternionLL.z, quaternionLL.w),
            rospy.Time.now(),
            "/base_laser",
            "/base_link")
            
        # odom -> base_link transformation
        self.odomBroadcaster.sendTransform(
            (self.x/1000, self.y/1000, 0),
            (quaternionOdom.x, quaternionOdom.y, quaternionOdom.z, quaternionOdom.w),
            rospy.Time.now(),
            "/base_link",
            "/odom")




    def odomUpdate(self):
        """ updates the odometry of the robot by using the measured
            wheel distances and wheelbase
        """
        WHEEL_BASE = 237.5 # measured in mm
        odom = NeatoOdom()
        
        LWheelMM = self.neato.state["LeftWheel_PositionInMM"]
        RWheelMM = self.neato.state["RightWheel_PositionInMM"]

        # calculate difference in position from last time
        Ldist = LWheelMM - self.prevL
        Rdist = RWheelMM - self.prevR

        # set new measurements to be the old ones
        self.prevL = LWheelMM
        self.prevR = RWheelMM
        
        dist = (Ldist + Rdist)/2.0
        self.theta    += (Ldist - Rdist)/WHEEL_BASE
        self.x        += dist * sin(self.theta)
        self.y        += dist * cos(self.theta)
        ##print self.x, self.y

        odom.__setattr__("theta", self.theta)
        odom.__setattr__('x', self.x)
        odom.__setattr__('y', self.y)

        self.odomPub.publish(odom)
Ejemplo n.º 26
0
class RoverpiOdometry:
    def __init__(self):
        self.x = 0.0
        self.y = 0.0
        self.th = 0.0
        self.vx = 0.0
        self.vy = 0.0
        self.vth = 0.0
        self.vx_max = 1.0
        self.vth_max = 1.0

        self.left_wheel_sub = rospy.Subscriber("lwheel_rpm", Int32,
                                               self.left_callback)
        self.right_wheel_sub = rospy.Subscriber("rwheel_rpm", Int32,
                                                self.right_callback)
        self.initial_pose_sub = rospy.Subscriber("initialpose",
                                                 PoseWithCovarianceStamped,
                                                 self.on_initial_pose)
        self.cmd_vel_sub = rospy.Subscriber("cmd_vel", Twist,
                                            self.cmd_vel_callback)

        self.odom_pub = rospy.Publisher("odom", Odometry, queue_size=100)
        self.odom_broadcaster = TransformBroadcaster()

        self.current_time = rospy.Time.now()
        self.previous_time = rospy.Time.now()

        self.last_cmd_time = None

    def on_initial_pose(self, msg):
        q = [
            msg.pose.pose.orientation.x, msg.pose.pose.orientation.x,
            msg.pose.pose.orientation.x, msg.pose.pose.orientation.w
        ]
        roll, pitch, yaw = euler_from_quaternion(q)

        self.x = msg.pose.pose.position.x
        self.y = msg.pose.pose.position.y
        self.th = yaw

    def left_callback(self, msg):
        print("Left Wheel RPM = %d", msg.data)

    def right_callback(self, msg):
        print("Right Wheel RPM = %d", msg.data)

    def cmd_vel_callback(self, msg):
        self.vx = max(min(msg.linear.x, self.vx_max), -self.vx_max)
        self.vth = max(min(msg.angular.z, self.vth_max), -self.vth_max)
        self.last_cmd_time = rospy.Time.now()

    def run(self):

        rate = rospy.Rate(10)

        while not rospy.is_shutdown():
            self.current_time = rospy.Time.now()

            if self.last_cmd_time == None or (
                    self.current_time - self.last_cmd_time).to_sec() > 1.0:
                rospy.loginfo("Did not get command for 1 second, stopping")
            else:
                # compute odometry in a typical way given the velocities of the robot
                dt = (self.current_time - self.previous_time).to_sec()

                delta_x = (self.vx * cos(self.th) -
                           self.vy * sin(self.th)) * dt
                delta_y = (self.vx * sin(self.th) +
                           self.vy * cos(self.th)) * dt
                delta_th = self.vth * dt

                self.x += delta_x
                self.y += delta_y
                self.th += delta_th

            # create quaternion from yaw
            odom_quat = quaternion_from_euler(0, 0, self.th)

            # publish the transform over tf
            self.odom_broadcaster.sendTransform((self.x, self.y, 0), odom_quat,
                                                self.current_time, "base_link",
                                                "odom")

            # construct odometry message
            odom = Odometry()
            odom.header.stamp = self.current_time
            odom.header.frame_id = "odom"
            odom.child_frame_id = "base_link"

            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.orientation.x = odom_quat[0]
            odom.pose.pose.orientation.y = odom_quat[1]
            odom.pose.pose.orientation.z = odom_quat[2]
            odom.pose.pose.orientation.w = odom_quat[3]

            odom.twist.twist.linear.x = self.vx
            odom.twist.twist.linear.y = self.vy
            odom.twist.twist.angular.z = self.vth

            # publish the message
            self.odom_pub.publish(odom)

            self.previous_time = self.current_time
            rate.sleep()
Ejemplo n.º 27
0
class DiffTf:
    #############################################################################

    #############################################################################
    def __init__(self):
        #############################################################################
        rospy.init_node("process")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)

        #### parameters #######
        self.rate = rospy.get_param("~rate", 50.0)  # the rate at which to publish the transform

        self.base_frame_id = rospy.get_param("~base_frame_id", "base_link")  # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param("~odom_frame_id", "odom")  # the name of the odometry reference frame
        self.laser_frame_id = rospy.get_param("~laser_frame_id", "laser_link")
        self.map_frame_id = rospy.get_param("~map_frame_id", "map")
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = rospy.Time.now() + self.t_delta

        # internal data

        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        self.th_pre = 0
        self.dx = 0  # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()

        self.qw = 0
        self.qx = 0
        self.qy = 0
        self.qz = 0
        self.laser = LaserScan()
        # subscriptions

        rospy.Subscriber("qx", Float32, self.qx_update)
        rospy.Subscriber("qy", Float32, self.qy_update)
        rospy.Subscriber("qz", Float32, self.qz_update)
        rospy.Subscriber("qw", Float32, self.qw_update)
        rospy.Subscriber("th", Float32, self.th_update)
        rospy.Subscriber("scan", LaserScan, self.laser_update)
        rospy.Subscriber("px", Float32, self.x_update)
        rospy.Subscriber("py", Float32, self.y_update)
        rospy.Subscriber("dx", Float32, self.dx_update)
        # rospy.Subscriber('dr',Float32,self.dr_update)
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.laserPub = rospy.Publisher("laser_scan", LaserScan, queue_size=20)
        self.odomBroadcaster = TransformBroadcaster()
        self.laserBroadcaster = TransformBroadcaster()

    #############################################################################
    def spin(self):
        #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    #############################################################################
    def update(self):
        #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()

            # this approximation works (in radians) for small angles
            th = self.th - self.th_pre

            self.dr = th / elapsed

            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = self.qx
            quaternion.y = self.qy
            quaternion.z = self.qz
            quaternion.w = self.qw
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (0, 0, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id,
            )

            self.laserBroadcaster.sendTransform(
                (0, 0, 0), (0, 0, 0, 1), rospy.Time.now(), self.laser_frame_id, self.base_frame_id
            )

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)
            laser = LaserScan()
            laser.header.stamp = now
            laser.header.frame_id = self.laser_frame_id
            laser.angle_min = self.laser.angle_min
            laser.angle_max = self.laser.angle_max
            laser.angle_increment = self.laser.angle_increment
            laser.time_increment = self.laser.time_increment
            laser.scan_time = self.laser.scan_time
            laser.range_min = self.laser.range_min
            laser.range_max = self.laser.range_max
            laser.ranges = self.laser.ranges
            laser.intensities = self.laser.intensities
            self.laserPub.publish(laser)

    def qx_update(self, msg):
        self.qx = msg.data

    def qy_update(self, msg):
        self.qy = msg.data

    def qz_update(self, msg):
        self.qz = msg.data

    def qw_update(self, msg):
        self.qw = msg.data

    def th_update(self, msg):
        self.th_pre = self.th
        self.th = msg.data

    def laser_update(self, msg):
        self.laser = msg

    def x_update(self, msg):
        self.x = msg.data

    def y_update(self, msg):
        self.y = msg.data

    def dx_update(self, msg):
        self.dx = msg.data
Ejemplo n.º 28
0
class ARbotController:
    def __init__(self, arduino):
        self.arduino = arduino
        self.stopped = False
        
        self.cmd = 1

        self.forwardSpeed = 0
        self.angularSpeed = 0
                 
        # Subscribe to cmd_vel
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)
        rospy.Subscriber("cmd_vel2", Twist, self.cmdVel2Callback)
        s = rospy.Service("pick_cmd_vel", PickCmdVel, self.pickCmdVel)

        # Subscribe to arbot_play_led and arbot_advance_led
        rospy.Subscriber("arbot_play_led", Bool, self.arbotPlayLedCallback)
        rospy.Subscriber("arbot_advance_led", Bool, self.arbotAdvanceLedCallback)
        
        # Setup the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        
        # Setup blob publisher
#        self.blob_publisher = rospy.Publisher('blobs', Blobs, queue_size=10)
        rospy.loginfo("Started ARbot controller.")
        
    def poll(self):
        (x, y, theta) = self.arduino.arbot_read_odometry()

        quaternion = Quaternion()
        quaternion.x = 0.0 
        quaternion.y = 0.0
        quaternion.z = sin(theta / 2.0)
        quaternion.w = cos(theta / 2.0)
    
        # Create the odometry transform frame broadcaster.
        now = rospy.Time.now()
        self.odomBroadcaster.sendTransform(
            (x, y, 0), 
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            now,
            "base_link",
            "odom"
            )
    
        odom = Odometry()
        odom.header.frame_id = "odom"
        odom.child_frame_id = "base_link"
        odom.header.stamp = now
        odom.pose.pose.position.x = x
        odom.pose.pose.position.y = y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        
        odom.twist.twist.linear.x = self.forwardSpeed
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = self.angularSpeed

        self.arduino.arbot_set_velocity(self.forwardSpeed, self.angularSpeed)

        self.odomPub.publish(odom)

#        blobs = self.arduino.get_blobs()
#        blobs.header.stamp = rospy.Time.now()
#        self.blob_publisher.publish(blobs)
            
    def stop(self):
        self.stopped = True
        self.forwardSpeed = 0
        self.angularSpeed = 0
        self.arduino.arbot_set_velocity(0, 0)
            
    def cmdVelCallback(self, cmd_vel):
        if self.cmd == 2:
            return
        self.forwardSpeed = cmd_vel.linear.x         # m/s
        self.angularSpeed = cmd_vel.angular.z        # rad/s

    def cmdVel2Callback(self, cmd_vel2):
        if self.cmd == 1:
            return
        self.forwardSpeed = cmd_vel2.linear.x
        self.angularSpeed = cmd_vel2.angular.z

    def pickCmdVel(self, req):
        self.cmd = req.cmd_vel
        #print "got cmd_vel: {0}".format(req.cmd_vel)
        return PickCmdVelResponse(req.cmd_vel)
        
    def arbotPlayLedCallback(self, msg):
        self.arduino.arbot_set_play_led(mgs.data)    
    def arbotAdvanceLedCallback(self, msg):
        self.arduino.arbot_set_advance_led(msg.data)
Ejemplo n.º 29
0
def wheelsOdomSendCmd():

	global linearVelocityCmd
	global angularVelocityCmd
	global lastCmdVelTime
	
	
	pubOdom=rospy.Publisher('odom', Odometry, queue_size=2)
	pubOdomBroadcaster = TransformBroadcaster()
	rospy.init_node('wheels', anonymous = True)
	rate =rospy.Rate(200)
	lastCmdVelTime=rospy.Time.now()

	wheelBase=rospy.get_param("~distance_between_wheels")
	ticksPerRev=rospy.get_param("~wheel_encoder_ticks_per_revolution")
	wheelCircumference=rospy.get_param("~drive_wheel_circumference")
	
	baseFrame=rospy.get_param("~base_frame")
	port=(rospy.get_param("~port_wheels_motordriver"))
	address=rospy.get_param("~address_wheels_motordriver",0X80)
	sendToMDRate=rospy.get_param("~rate_to_send_cmd_vel_to_motor_driver",30.0)
	nseconds=1000000000/sendToMDRate
	timeBetweenMDCMD=rospy.Duration(0, nseconds)
	MDtime=rospy.Time.now()

	

	

	metersToTicks=ticksPerRev/wheelCircumference
	ticksToMeters=wheelCircumference/ticksPerRev

	#establish connection to Motor driver
	start_connect = time.time()
	TIMEOUT=False
	while TIMEOUT==False:
		try:
			roboclaw.Open(port,115200)#/dev/roboclaw_wheels
			break
		except Exception as e:
			if time.time()-start_connect > 60:
				rospy.logfatal("failed to connect to wheels motor driver")
				TIMEOUT=True
				break
			print "Failed to connect to wheels motor driver, retrying...\n"
			time.sleep(5)
			pass



	version = roboclaw.ReadVersion(address)
	if version[0]==False:
		rospy.logfatal("get version of wheel motor driver failed")
	else:
		repr(version[1])
		rospy.loginfo("connected to motor driver")
	roboclaw.ResetEncoders(address)#set encoder values to 0
	roboclaw.SpeedM1M2(address,0,0)#set motor speed to 0


	lastLeftDistance=0.0
	lastRightDistance=0.0
	lastLeftSpeed=0.0
	lastRightSpeed=0.0
	yaw=0.0
	positionX=0
	positionY=0
	

	#setup subscriber
	rospy.Subscriber("/cmd_vel", Twist, cmdVelCallback)
	seconds=rospy.Time()

	while not rospy.is_shutdown():
		now = rospy.Time.now()
		try:
			lt=roboclaw.ReadEncM1(address)
			rt=roboclaw.ReadEncM2(address)
			ls=roboclaw.ReadSpeedM1(address)
			rs=roboclaw.ReadSpeedM1(address)

		except:
			version = roboclaw.ReadVersion(address)
			while version[0]==False:

				try:
					roboclaw.Open(port,115200)#/dev/roboclaw_wheels
				except rospy.ROSInterruptException:
					rospy.logwarn("failed to connect to wheels motor driver again afer it disconeced")
				pass
			rospy.sleep(0.05)

		
		leftDistance=lt[1]*ticksToMeters
		rightDistance=rt[1]*ticksToMeters
		leftSpeed=ls[1]*ticksToMeters
		rightSpeed=rs[1]*ticksToMeters

		#rospy.loginfo(" Left distance %d right distance %d", lt[1], rt[1])
		#rospy.loginfo("left %d right %d", leftDistance, rightDistance)

		dLeftDistance=leftDistance-lastLeftDistance
		dRightDistance=rightDistance-lastRightDistance
		rotation=(dRightDistance-dLeftDistance)/wheelBase
		

		dLeftSpeed=leftSpeed-lastLeftSpeed
		dRightSpeed=rightSpeed-lastRightSpeed
		rotationSpeed=(dRightSpeed-dLeftSpeed)/wheelBase

		averageDistance=(dRightDistance+dLeftDistance)/2.0
		averageVelocity=(dRightSpeed+dLeftSpeed)/2.0

		lastLeftDistance=leftDistance
		lastRightDistance=rightDistance
		lastLeftSpeed=leftSpeed
		lastRightDistance=rightDistance

		if (averageDistance !=0) :
			dx=cos(rotation)*averageDistance
			dy=-sin(rotation)*averageDistance
			positionX += cos(yaw)*dx-sin(yaw)*dy
			positionY +=sin(yaw)*dx+cos(yaw)*dy

		if(rotation != 0):
			yaw+=rotation

		quaternion=Quaternion()
		quaternion.x=0.0
		quaternion.y=0.0
		quaternion.z=sin(yaw/2.0)
		quaternion.w=cos(yaw/2.0)

		# Create the odometry transform frame broadcaster.
		pubOdomBroadcaster.sendTransform(
			(positionX, positionY, 0),
			(quaternion.x, quaternion.y, quaternion.z, quaternion.w),
			rospy.Time.now(),
			baseFrame,
			"odom"
			)

		#rospy.loginfo(" linear %f angular %f", linearVelocityCmd, angularVelocityCmd)

		
		odom = Odometry()

		odom.header.frame_id = "odom"
		odom.child_frame_id = baseFrame
		odom.header.stamp = now
		odom.pose.pose.position.x = positionX
		odom.pose.pose.position.y = positionY
		odom.pose.pose.position.z = 0
		odom.pose.pose.orientation = quaternion
		odom.twist.twist.linear.x = averageVelocity

		odom.twist.twist.linear.y = 0
		odom.twist.twist.angular.z = rotationSpeed

		pubOdom.publish(odom)


		#get desired wheel velocities
		
		if (rospy.Time.now()-MDtime)>=timeBetweenMDCMD:
			MDtime=rospy.Time.now()
		
			x = linearVelocityCmd        # m/s
			th = angularVelocityCmd      # rad/s
			#rospy.loginfo ("Linear cmd %f , angular cmd %f", x, th)

			if x == 0:
				# Turn in place
				right = th * wheelBase  / 2.0
				left = -right

			elif th == 0:
				# Pure forward/backward motion
				left = right = x
			else:
				# Rotation about a point in space
				left = x - th * wheelBase/ 2.0
				right = x + th * wheelBase / 2.0

			try:
				left=int(left*metersToTicks)
				right=int(right*metersToTicks)
			except:
				left = 0
				right = 0
			
			
			
			

			try:
				roboclaw.SpeedM1M2(address,left,right)

			except:
				version = roboclaw.ReadVersion(address)
				while version[0]==False:

					try:
						roboclaw.Open(port,115200)#/dev/roboclaw_wheels
					except:
						rospy.logwarn("failed to connect to wheels motor driver again afer it disconeced")
						pass
					rospy.sleep(0.05)
		
		rate.sleep()





	# turn off motors if ros is shutdown
	roboclaw.SpeedM1M2(address,0,0)
Ejemplo n.º 30
0
class WheelchairTf:
    #############################################################################

    #############################################################################
    def __init__(self):
        #############################################################################
        rospy.init_node("wheelchair_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)

        #### parameters #######
        self.rate = rospy.get_param(
            '~rate', 20.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param(
            'ticks_meter',
            3776.52))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param(
            '~base_width', 0.615))  # The wheel base width in meters

        self.base_frame_id = rospy.get_param(
            '~base_frame_id',
            'base_footprint')  # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param(
            '~odom_frame_id',
            'odom')  # the name of the odometry reference frame

        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param(
            'wheel_low_wrap',
            (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min)
        self.encoder_high_wrap = rospy.get_param(
            'wheel_high_wrap',
            (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min)

        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = rospy.Time.now() + self.t_delta

        # internal data
        self.enc_left = None  # wheel encoder readings
        self.enc_right = None
        self.left = 0  # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0  # orientation in radians
        self.prev_th = 0  # previous orientation in radians
        self.dx = 0  # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()
        self.first_instance = 1
        self.th_offset = 0

        # subscriptions
        rospy.Subscriber("lwheel", Int16, self.lwheelCallback)
        rospy.Subscriber("rwheel", Int16, self.rwheelCallback)

        rospy.Subscriber("kalmanOutput", Float32, self.thetaCallback)
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

    #############################################################################
    def spin(self):
        #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    #############################################################################
    def update(self):
        #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()

            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right

            # distance traveled is the average of the two wheels
            d = (d_left + d_right) / 2
            # this approximation works (in radians) for small angles
            #th = ( d_right - d_left ) / self.base_width
            th = self.th - self.prev_th
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed

            if (d != 0):
                # calculate distance traveled in x and y
                x = cos(self.th) * d
                y = sin(self.th) * d
                # calculate the final position of the robot
                self.x = self.x + x
                self.y = self.y + y

            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2)
            quaternion.w = cos(self.th / 2)
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(), self.base_frame_id, self.odom_frame_id)

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)

    #############################################################################
    def lwheelCallback(self, msg):
        #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap
                and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1

        if (enc > self.encoder_high_wrap
                and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1

        self.left = 1.0 * (enc + self.lmult *
                           (self.encoder_max - self.encoder_min))

        #rospy.loginfo(msg.data)
        self.prev_lencoder = enc

    #############################################################################
    def rwheelCallback(self, msg):
        #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap
                and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1

        if (enc > self.encoder_high_wrap
                and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1

        self.right = 1.0 * (enc + self.rmult *
                            (self.encoder_max - self.encoder_min))

        self.prev_rencoder = enc

#############################################################################

    def thetaCallback(self, msg):

        #############################################################################
        if (self.first_instance < 50):
            self.th_offset = msg.data
        self.first_instance += 1
        if (self.first_instance > 100):
            self.first_instance = 100
        self.prev_th = self.th
        #self.th = msg.data
        self.th = (msg.data - self.th_offset) * (3.1415 / 180.0)
Ejemplo n.º 31
0
class NeatoNode:

    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        self.port = rospy.get_param('~port', "/dev/ttyUSB0")
        rospy.loginfo("Using port: %s"%(self.port))

        self.robot = xv11(self.port)

        rospy.Subscriber("pi_cmd",String,self.pi_command)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('scan', LaserScan, queue_size=10)
        self.odomPub = rospy.Publisher('odom',Odometry, queue_size=10)
        self.bumpPub = rospy.Publisher('bump',Bump, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_to_send = None

        self.cmd_vel = [0,0]

    def pi_command(self,msg):
        self.cmd_to_send = msg

    def spin(self):        
        encoders = [0,0]

        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0
        # NEED to reorder the laser scans and flip the laser around... this will not be intuitive for students!!

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id',ROBOT_NAME+'base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=ROBOT_NAME+scan_link)) 
        scan.angle_min = -pi
        scan.angle_max = pi
        scan.angle_increment = pi/180.0
        scan.range_min = 0.020
        scan.range_max = 5.0
        scan.time_increment = 1.0/(5*360)
        scan.scan_time = 0.2
        odom = Odometry(header=rospy.Header(frame_id=ROBOT_NAME+"odom"), child_frame_id=ROBOT_NAME+'base_link')
    
        # main loop of driver
        r = rospy.Rate(5)
        iter_count = 0
        rospy.sleep(4)
        #self.robot.requestScan()
        scan.header.stamp = rospy.Time.now()
        last_motor_time = rospy.Time.now()
        total_dth = 0.0
        while not rospy.is_shutdown():
            #print "spinning"
            iter_count += 1
            if self.cmd_to_send != None:
                self.robot.send_command(self.cmd_to_send)
                self.cmd_to_send = None

            t_start = time.time()
            self.robot.requestScan()
            #time.sleep(.01)
            delta_t = (rospy.Time.now() - scan.header.stamp).to_sec()
            if delta_t-0.2 > 0.1:
                print "Iteration took longer than expected (should be 0.2) ", delta_t
            scan.header.stamp = rospy.Time.now()
            (scan.ranges, scan.intensities) = self.robot.getScanRanges()
            # repeat last measurement to simulate -pi to pi (instead of -pi to pi - pi/180)
            scan.ranges.append(scan.ranges[0])
            scan.intensities.append(scan.intensities[0])
            #print 'Got scan ranges %f' % (time.time() - t_start)

            # get motor encoder values
            curr_motor_time = rospy.Time.now()
            t_start = time.time()
            try:
                start_t = rospy.Time.now()
                left, right, left_speed, right_speed = self.robot.getMotors()
                delta_t = (rospy.Time.now() - scan.header.stamp).to_sec()
                # now update position information
                # might consider moving curr_motor_time down
                dt = (curr_motor_time - last_motor_time).to_sec()
                last_motor_time = curr_motor_time

                d_left = (left - encoders[0])/1000.0
                d_right = (right - encoders[1])/1000.0
                # might consider using speed instead!
                #print d_left, d_right, left_speed*dt/1000.0, right_speed*dt/1000.0
                #d_left, d_right = left_speed*dt/1000.0, right_speed*dt/1000.0
                encoders = [left, right]
                dx = (d_left+d_right)/2
                dth = (d_right-d_left)/(BASE_WIDTH/1000.0)
                total_dth += dth

                x = cos(dth)*dx
                y = -sin(dth)*dx

                self.x += cos(self.th)*x - sin(self.th)*y
                self.y += sin(self.th)*x + cos(self.th)*y
                self.th += dth

                # prepare tf from base_link to odom
                quaternion = Quaternion()
                quaternion.z = sin(self.th/2.0)
                quaternion.w = cos(self.th/2.0)

                # prepare odometry
                odom.header.stamp = curr_motor_time
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = dx/dt
                odom.twist.twist.angular.z = dth/dt
                self.odomBroadcaster.sendTransform( (self.x, self.y, 0), (quaternion.x, quaternion.y, quaternion.z, quaternion.w), curr_motor_time, ROBOT_NAME+"base_link", ROBOT_NAME+"odom" )
                self.odomPub.publish(odom)
                #print 'Got motors %f' % (time.time() - t_start)
            except Exception as err:
                print "my error is " + str(err)
            t_start = time.time()           
            self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1], max(abs(self.cmd_vel[0]),abs(self.cmd_vel[1])))
            try:
                bump_sensors = self.robot.getDigitalSensors()
                self.bumpPub.publish(Bump(leftFront=bump_sensors[0],leftSide=bump_sensors[1],rightFront=bump_sensors[2],rightSide=bump_sensors[3]))
            except:
                print "failed to get bump sensors!"
            # # send updated movement commands
            #print 'Set motors %f' % (time.time() - t_start)

            # publish everything
            #print "publishing scan!"
            self.scanPub.publish(scan)
            # wait, then do it again
            r.sleep()

    def cmdVelCb(self,req):
        x = req.linear.x * 1000
        th = req.angular.z * (BASE_WIDTH/2) 
        k = max(abs(x-th),abs(x+th))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            x = x*MAX_SPEED/k; th = th*MAX_SPEED/k
        self.cmd_vel = [ int(x-th) , int(x+th) ]
Ejemplo n.º 32
0
class SEMAPEnvironmentServices():

  server = None
  objects = {}
  tf_broadcaster = None
  tf_listener = None
  marker_pub = None
  range_query2d_marker = None
  range_query3d_marker = None
  range_query_marker = None
  area_query_marker = None
  volume_query_marker = None

  def __init__(self):
    self.setup_node()
    self.server = InteractiveMarkerServer("semap_environment")
    self.tf_broadcaster = TransformBroadcaster()
    self.tf_listener = TransformListener()

  def setup_node(self):
      rospy.init_node('semap_environment_services')
      rospy.loginfo( "SEMAP Environment Services are initializing...\n" )

      rospy.Timer(rospy.Duration(0.02), self.publishTF)
      #rospy.Timer(rospy.Duration(1.0), self.activate_robot_surroundings)
      rospy.Subscriber("create_object", PoseStamped, self.createObjectCb)
      #rospy.Subscriber("polygon", PolygonStamped, self.findObjectWithinPolygonCb)
      #rospy.Subscriber("polygon", PolygonStamped, self.copyObjectWithinPolygonCb)
      rospy.Subscriber("polygon", PolygonStamped, self.findObjectWithinVolumeCb)
      rospy.Subscriber("range2d", PointStamped, self.findObjectWithinRange2DCb)
      rospy.Subscriber("range_query", PointStamped, self.findObjectWithinRangeCb)

      self.range_query_marker = rospy.Publisher("distance_query", MarkerArray, queue_size=10)
      self.area_query_marker = rospy.Publisher("area_query", PolygonStamped, queue_size=10)
      self.volume_query_marker = rospy.Publisher("volume_query", MarkerArray, queue_size=10)

      self.range_query2d_marker = rospy.Publisher("range_query2d_marker", Marker, queue_size=10)
      self.marker_pub = rospy.Publisher("collection_marker", MarkerArray, queue_size=10)

      user = rospy.get_param('~user')
      password = rospy.get_param('~password')
      host = rospy.get_param('~host')
      database = rospy.get_param('~database')

      initializeConnection(user, password, host, database, False)

      ## Active Objects
      srv_refresh_objects = rospy.Service('refresh_objects', ActivateObjects, self.refresh_objects)
      srv_refresh_all_objects = rospy.Service('refresh_all_objects', ActivateAllObjects, self.refresh_all_objects)
      srv_activate_objects = rospy.Service('activate_objects', ActivateObjects, self.activate_objects)
      srv_activate_all_objects = rospy.Service('activate_all_objects', ActivateAllObjects, self.activate_all_objects)
      srv_deactivate_objects = rospy.Service('deactivate_objects', DeactivateObjects, self.deactivate_objects)
      srv_deactivate_all_object = rospy.Service('deactivate_all_objects', DeactivateAllObjects, self.deactivate_all_objects)
      srv_show_objects = rospy.Service('show_objects', ActivateObjects, self.show_objects)
      srv_show_all_objects = rospy.Service('show_all_objects', ActivateAllObjects, self.show_all_objects)
      #srv_unshow_objects = rospy.Service('unshow_objects', ActivateObjects, self.activate_all_objects)
      #srv_unshow_all_objects = rospy.Service('unshow_all_objects', ActivateAllObjects, self.activate_all_objects)

      srv_show_distance_between_objects = rospy.Service('show_distance_between_objects', GetDistanceBetweenObjects, self.showDistanceBetweenObjects)
      srv_show_objects_within_range = rospy.Service('show_objects_within_range', GetObjectsWithinRange, self.showObjectWithinRange)
      srv_show_objects_within_area = rospy.Service('show_objects_within_area', GetObjectsWithinArea, self.showObjectWithinArea)
      srv_show_objects_within_volume = rospy.Service('show_objects_within_volume', GetObjectsWithinVolume, self.showObjectWithinVolume)

      srv_activate_objects_in_objects = rospy.Service('activate_objects_in_objects', GetObjectsInObjects, self.activateObjectsInObjects)
      srv_show_objects_in_objects = rospy.Service('show_objects_in_objects', GetObjectsInObjects, self.showObjectsInObjects)

      srv_activate_objects_on_objects = rospy.Service('activate_objects_on_objects', GetObjectsOnObjects, self.activateObjectsOnObjects)
      srv_show_objects_on_objects = rospy.Service('show_objects_on_objects', GetObjectsOnObjects, self.showObjectsOnObjects)

      rospy.loginfo( "SEMAP DB Services are running...\n" )

  def spin(self):
      rospy.spin()

  ### Services
  def activate_objects(self, req):
    then = rospy.Time.now()
    if len( req.ids) > 0:
      rospy.loginfo("SpatialEnv SRVs: activate_objects")
      #self.deactivate_objects(req)
      get_res = call_get_object_instances(req.ids)
      rospy.loginfo("Call Get Object Instances took %f seconds" % (rospy.Time.now() - then).to_sec())
      for obj in get_res.objects:

        #rospy.loginfo("Activate object: %s" % obj.name)

        # get inst visu from db
        # if exits: convertNonDBtype
        # else create one, store and pass on

        if obj.name in self.objects.keys():
          #if self.objects[obj.name].status == "active":
            #print 'object', obj.name, 'is already active and gets reactivated'
          if self.objects[obj.name].status == "inactive":
            del self.objects[obj.name]
            #print 'object', obj.name, 'is inactive and gets removed from inactive pool'
        #else:
        #  print 'object was unknown so far, now its active'

        then2 = rospy.Time.now()
        active_object = EnvironmentObject(obj.id, obj.name, obj, InteractiveObjectMarker(obj, self.server, None ), status = "active")
        #rospy.loginfo("Marker took %f seconds" % (rospy.Time.now() - then2).to_sec())
        self.objects[obj.name] = active_object



        #rospy.loginfo("Took %f seconds" % (rospy.Time.now() - now).to_sec())
      self.publishTF(None)
      rospy.loginfo("Took %f seconds" % (rospy.Time.now() - then).to_sec())
      rospy.loginfo("SpatialEnv SRVs: activate_objects - done")
    return ActivateObjectsResponse()

  def show_objects(self, req):
    if len( req.ids) > 0:
      rospy.loginfo("SpatialEnv SRVs: show_objects")
      get_res = call_get_object_instances(req.ids)
      for obj in get_res.objects:
        if obj.name in self.objects.keys():
          if self.objects[obj.name].status == "active":
            print 'object', obj.name, 'is already active'
            break
          elif self.objects[obj.name].status == "inactive":
            print 'object', obj.name, 'is inactive'
            ghost = EnvironmentObject(obj.id, obj.name, obj, GhostObjectMarker(obj, self.server, None ), status = "inactive")
            self.objects[obj.name] = ghost
        else:
          print 'object was unknown so far, now its inactive'
          ghost = EnvironmentObject(obj.id, obj.name, obj, GhostObjectMarker(obj, self.server, None ), status = "inactive")
          self.objects[obj.name] = ghost
      rospy.loginfo("SpatialEnv SRVs: show_objects - done")
    return ActivateObjectsResponse()

  def refresh_objects(self, req):
    rospy.loginfo("SpatialEnv SRVs: reactivate_objects")
    print req.ids
    active_req = ActivateObjectsRequest()
    inactive_req = ActivateObjectsRequest()

    for key in self.objects.keys():
      if self.objects[key].id in req.ids:
        if self.objects[key].status == "active":
          active_req.ids.append( self.objects[key].id )
        elif self.objects[key].status == "inactive":
          inactive_req.ids.append( self.objects[key].id )

    self.activate_objects(active_req)
    self.show_objects(inactive_req)

    res = ActivateObjectsResponse()
    rospy.loginfo("SpatialEnv SRVs: reactivate_objects - done")
    return res

  def refresh_all_objects(self, req):
    rospy.loginfo("SpatialEnv SRVs: reactivate_all_objects")
    active_req = ActivateObjectsRequest()
    inactive_req = ActivateObjectsRequest()

    for key in self.objects.keys():
      if self.objects[key].status == "active":
        active_req.ids.append( self.objects[key].id )
      elif self.objects[key].status == "inactive":
        inactive_req.ids.append( self.objects[key].id )

    self.activate_objects(active_req)
    self.show_objects(inactive_req)

    res = ActivateAllObjectsResponse()
    rospy.loginfo("SpatialEnv SRVs: reactivate_all_objects - done")
    return res

  def deactivate_objects(self, req):
    rospy.loginfo("SpatialEnv SRVs: deactivate_objects")
    res = DeactivateObjectsResponse()
    inactive_req = ActivateObjectsRequest()
    for key in self.objects.keys():
      if self.objects[key].id in req.ids:
        del self.objects[key]
    self.show_objects(req)
    self.publishTF(None)
    return res

  def deactivate_all_objects(self, req):
    rospy.loginfo("SpatialEnv SRVs: deactivate_all_objects")
    self.objects = {}
    self.publishTF(None)
    self.show_all_objects(req)
    return DeactivateAllObjectsResponse()

  def activate_all_objects(self, req):
      rospy.loginfo("SpatialEnv SRVs: activate_all_objects")
      ids = db().query(ObjectInstance.id).all()
      req = ActivateObjectsRequest()
      req.ids = [id for id, in ids]
      self.activate_objects(req)
      res = ActivateAllObjectsResponse()
      rospy.loginfo("SpatialEnv SRVs: activate_all_objects - done")
      return res

  def show_all_objects(self, req):
      rospy.loginfo("SpatialEnv SRVs: show_all_objects")
      ids = db().query(ObjectInstance.id).all()
      req = ActivateObjectsRequest()
      req.ids = [id for id, in ids]
      self.show_objects(req)
      res = ActivateAllObjectsResponse()
      rospy.loginfo("SpatialEnv SRVs: show_all_objects - done")
      return res

  def publishTF(self, msg):
      if len(self.objects) > 0:
        for key in self.objects.keys():
          if self.objects[key].status == "active":
            object = self.objects[key].object
            translation = object.pose.pose.position
            rotation = object.pose.pose.orientation
            time = rospy.Time.now()
            #print 'publish tf'
            self.tf_broadcaster.sendTransform( (translation.x, translation.y, translation.z), \
                                          (rotation.x, rotation.y, rotation.z, rotation.w), \
                                          time, object.name, object.pose.header.frame_id)

  def activate_robot_surroundings(self, msg):

    #if activate_robot_surroundings:
      try:
        (trans,rot) = self.tf_listener.lookupTransform('/world', '/base_link', rospy.Time(0))
        print 'current robot position', trans
      except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
        print 'could not determine current robot position'
    #else:
    #  robot inactive

  def createObjectCb(self, pose):
    print 'Create Object from RViz pose'
    app = QApplication(sys.argv)
    widget = ChooseObjectDescriptionWidget(0)
    widget.show()
    app.exec_()
    desc_name, desc_id = widget.getChoice()
    del app, widget

    if(desc_id == -1):
      new_desc = ROSObjectDescription()
      new_desc.type = desc_name
      res = call_add_object_descriptions( [ new_desc ] )
      print res
      desc_id = res.ids[0]

    obj = ROSObjectInstance()
    obj.description.id = desc_id
    obj.pose = pose

    res = call_add_object_instances( [obj] )
    call_activate_objects( res.ids )

  def activateObjectsInObjects(self, req):
    res = call_get_objects_in_objects(req.reference, req.target, req.fully_within)
    ids = []
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)
    call_activate_objects( ids )
    return res

  def showObjectsInObjects(self, req):
    res = call_get_objects_in_objects(req.reference, req.target, req.fully_within)
    ids = []
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)
    call_show_objects( ids )
    return res

  def activateObjectsOnObjects(self, req):
    print 'GOT SO FAR'
    res = call_get_objects_on_objects(req.reference_object_types, req.target_object_types, req.threshold)
    print 'NOW WHAT'
    ids = []
    for pair in res.pairs:
      #if pair.reference_id not in ids:
      #  ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)
    call_activate_objects( ids )
    return res

  def showObjectsOnObjects(self, req):
    print 'GOT SO FAR'
    res = call_get_objects_on_objects(req.reference_object_types, req.target_object_types, req.threshold)
    print 'NOW WHAT'
    ids = []
    for pair in res.pairs:
      #if pair.reference_id not in ids:
      #  ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)
    call_show_objects( ids )
    return res

  def findObjectWithinRange2DCb(self, point_stamped):
    distance = 2.0
    print 'find Objects Within Range2D'
    #res = call_get_objects_within_range2d([], "Position2D", point_stamped.point, distance, fully_within = False)
    #res = call_get_objects_within_range2d([], "FootprintBox", point_stamped.point, distance, fully_within = False)
    #res = call_get_objects_within_range2d(["ConferenceTable", "ConferenceChair"], "Position2D", point_stamped.point, 3.0)
    #call_activate_objects( res.ids )

    marker = Marker()
    marker.header.frame_id = "world"
    marker.header.stamp = rospy.get_rostime()
    marker.ns = "2d_range_query_marker"
    marker.id = 0
    marker.type = 3 #cylinder
    marker.scale.x = distance*2
    marker.scale.y = distance*2
    marker.scale.z = 0.01
    marker.pose.position = point_stamped.point
    marker.pose.position.z = 0.0
    marker.color.r = 0.0
    marker.color.g = 1.0
    marker.color.b = 0.0
    marker.color.a = 0.5
    self.range_query2d_marker.publish(marker)

  def findObjectWithinRangeCb(self, point_stamped):
    distance = 1.5
    res = call_get_objects_within_range(point_stamped.point, [], "FootprintHull", distance, fully_within = False)
    ids = []
    array = MarkerArray()

    marker = Marker()
    marker.header.frame_id = "world"
    marker.header.stamp = rospy.get_rostime()
    marker.ns = "range"
    marker.id = 0
    marker.type = 3 #sphere
    marker.scale.x = distance*2
    marker.scale.y = distance*2
    marker.scale.z = 0.005
    marker.pose.position = point_stamped.point
    marker.pose.position.z = 0.0
    marker.color.r = 0.25
    marker.color.g = 0.25
    marker.color.b = 0.75
    marker.color.a = 0.5
    array.markers.append(marker)

    lines = Marker()
    lines.header.frame_id = "world"
    lines.header.stamp = rospy.get_rostime()
    lines.ns = "lines"
    lines.id = 0
    lines.type = 5 #line list
    lines.scale.x = 0.05
    lines.scale.y = 0.0
    lines.scale.z = 0.0
    lines.color.r = 0.75
    lines.color.g = 0.750
    lines.color.b = 0.750
    lines.color.a = 1.0
    for pair in res.pairs:
      lines.points += pair.min_dist_line
      lines.points += pair.max_dist_line

      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

      lines.colors.append(lines.color)
      text = Marker()
      text.header.frame_id = "world"
      text.header.stamp = rospy.get_rostime()
      text.ns = "distances"
      text.id = 0
      text.type = 9 #line list
      text.pose.position.x = (pair.min_dist_line[1].x + pair.min_dist_line[0].x)/2
      text.pose.position.y = (pair.min_dist_line[1].y + pair.min_dist_line[0].y)/2
      text.pose.position.z = (pair.min_dist_line[1].z + pair.min_dist_line[0].z)/2 + 0.05
      text.scale.z = 0.2
      text.color.r = 1.0
      text.color.g = 1.0
      text.color.b = 1.0
      text.color.a = 1.0
      text.text = str(round(pair.min_dist,3))
      array.markers.append(text)
    array.markers.append(lines)
    id = 0
    for m in array.markers:
      m.id = id
      id += 1
    self.range_query_marker.publish(array)
    call_activate_objects( ids )

  def showObjectWithinRange(self, req):
    res = call_get_objects_within_range(req.reference_point, req.target_object_types, req.target_object_geometry_type,
                                              req.distance, req.fully_within)

    ids = []
    array = MarkerArray()

    marker = Marker()
    marker.header.frame_id = "world"
    marker.header.stamp = rospy.get_rostime()
    marker.ns = "range"
    marker.id = 0
    marker.type = 3 #sphere
    marker.scale.x = req.distance*2
    marker.scale.y = req.distance*2
    marker.scale.z = 0.005
    marker.pose.position = req.reference_point
    marker.pose.position.z = 0.0
    marker.color.r = 0.25
    marker.color.g = 0.25
    marker.color.b = 0.75
    marker.color.a = 0.5
    array.markers.append(marker)

    lines = Marker()
    lines.header.frame_id = "world"
    lines.header.stamp = rospy.get_rostime()
    lines.ns = "lines"
    lines.id = 0
    lines.type = 5 #line list
    lines.scale.x = 0.05
    lines.scale.y = 0.0
    lines.scale.z = 0.0
    lines.color.r = 0.75
    lines.color.g = 0.750
    lines.color.b = 0.750
    lines.color.a = 1.0
    for pair in res.pairs:
      lines.points += pair.min_dist_line
      lines.points += pair.max_dist_line

      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

      lines.colors.append(lines.color)
      text = Marker()
      text.header.frame_id = "world"
      text.header.stamp = rospy.get_rostime()
      text.ns = "distances"
      text.id = 0
      text.type = 9 #line list
      text.pose.position.x = (pair.min_dist_line[1].x + pair.min_dist_line[0].x)/2
      text.pose.position.y = (pair.min_dist_line[1].y + pair.min_dist_line[0].y)/2
      text.pose.position.z = (pair.min_dist_line[1].z + pair.min_dist_line[0].z)/2 + 0.05
      text.scale.z = 0.2
      text.color.r = 1.0
      text.color.g = 1.0
      text.color.b = 1.0
      text.color.a = 1.0
      text.text = str(round(pair.min_dist,3))
      array.markers.append(text)
    array.markers.append(lines)
    id = 0
    for m in array.markers:
      m.id = id
      id += 1
    self.range_query_marker.publish(array)
    call_activate_objects( ids )
    return res

  def findObjectWithinVolumeCb(self, polygon_stamped):
    extrude = call_extrude_polygon(polygon_stamped.polygon, 0.0, 0.0, 0.9)
    mesh = PolygonMeshStamped()
    mesh.header.frame_id = "world"
    mesh.mesh = extrude.mesh
    print extrude.mesh
    res = call_get_objects_within_volume(extrude.mesh, ['Mug','Teapot','Monitor','Keyboard'], 'BoundingBox', True)
    ids=[]
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

    call_activate_objects( ids )

    array = MarkerArray()
    pose = ROSPoseStamped()
    pose.header.frame_id = 'world'
    for polygon in extrude.mesh.polygons:
        poly = Polygon()
        for point in polygon.vertex_indices:
          poly.points.append(extrude.mesh.vertices[point])
        geo_marker = create_polygon_marker("VolumeQuery", pose, [0,1.0,0,1.0], [0.01, 0.01, 0.01], poly)
        array.markers.append(geo_marker)

    id = 0
    for m in array.markers:
      m.header.frame_id = 'world'
      m.id = id
      id += 1

    self.volume_query_marker.publish(array)

  def showObjectWithinVolume(self, req):
    res = call_get_objects_within_volume(req.reference_mesh, req.target_object_types, req.target_object_geometry_type, req.fully_within)

    ids=[]
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

    call_activate_objects( ids )

    array = MarkerArray()
    pose = ROSPoseStamped()
    pose.header.frame_id = 'world'
    for polygon in req.reference_mesh.polygons:
        poly = Polygon()
        for point in polygon.vertex_indices:
          poly.points.append(req.reference_mesh.vertices[point])
        geo_marker = create_polygon_marker("VolumeQuery", pose, [0,1.0,0,1.0], [0.01, 0.01, 0.01], poly)
        array.markers.append(geo_marker)

    id = 0
    for m in array.markers:
      m.header.frame_id = 'world'
      m.id = id
      id += 1

    self.volume_query_marker.publish(array)


    return res

  def findObjectWithinPolygonCb(self, polygon_stamped):
    res = call_get_objects_within_area(polygon_stamped.polygon, ["Chair"], "Position2D", fully_within = False)
    ids=[]
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

    call_activate_objects( ids )
    self.area_query_marker.publish(polygon_stamped)
    return res

  def copyObjectWithinPolygonCb(self, polygon_stamped):
    res = call_get_objects_within_area(polygon_stamped.polygon, [], "Position2D", fully_within = False)
    ids=[]
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

    print 'COPY'
    copy_res = call_copy_object_instances(ids)

    if len( copy_res.ids ) > 1:
      print 'copy_res', copy_res
      obj_res = call_get_object_instances( [copy_res.ids[0]] )
      print 'bind to ', obj_res.objects[0].name

      frame = obj_res.objects[0].name
      for id in copy_res.ids:
        if id != obj_res.objects[0].id:
          print 'bind', id, 'to', obj_res.objects[0].id
          call_change_frame(id, frame, False)

    call_activate_objects( copy_res.ids )
    call_refresh_objects( copy_res.ids )
    return res

  def showObjectWithinArea(self, req):
    res = call_get_objects_within_area(req.reference_polygon, req.target_object_types, req.target_object_geometry_type, req.fully_within)
    ids=[]
    for pair in res.pairs:
      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

    call_activate_objects( ids )
    polygon_stamped = PolygonStamped()
    polygon_stamped.header.frame_id = "world"
    polygon_stamped.polygon = req.reference_polygon
    self.area_query_marker.publish(polygon_stamped)
    return res

  def showDistanceBetweenObjects(self, req):
    res = call_get_distance_between_objects(req.reference_object_types, req.reference_object_geometry_type,
                                              req.target_object_types, req.target_object_geometry_type,
                                              req.min_range, req.max_range,
                                              req.sort_descending, req.max_distance, return_points = True)

    array = MarkerArray()

    lines = Marker()
    lines.header.frame_id = "world"
    lines.header.stamp = rospy.get_rostime()
    lines.ns = "lines"
    lines.id = 0
    lines.type = 5 #line list
    lines.scale.x = 0.05
    lines.scale.y = 0.0
    lines.scale.z = 0.0
    lines.color.r = 0.75
    lines.color.g = 0.750
    lines.color.b = 0.750
    lines.color.a = 1.0
    ids =[]
    for pair in res.pairs:
      lines.points += pair.min_dist_line
      lines.points += pair.max_dist_line

      if pair.reference_id not in ids:
        ids.append(pair.reference_id)
      if pair.target_id not in ids:
        ids.append(pair.target_id)

      lines.colors.append(lines.color)
      text = Marker()
      text.header.frame_id = "world"
      text.header.stamp = rospy.get_rostime()
      text.ns = "distances"
      text.id = 0
      text.type = 9 #line list
      text.pose.position.x = (pair.min_dist_line[1].x + pair.min_dist_line[0].x)/2
      text.pose.position.y = (pair.min_dist_line[1].y + pair.min_dist_line[0].y)/2
      text.pose.position.z = (pair.min_dist_line[1].z + pair.min_dist_line[0].z)/2 + 0.05
      text.scale.z = 0.2
      text.color.r = 1.0
      text.color.g = 1.0
      text.color.b = 1.0
      text.color.a = 1.0
      text.text = str(round(pair.min_dist,3))
      array.markers.append(text)
    array.markers.append(lines)
    id = 0
    for m in array.markers:
      m.id = id
      id += 1
    self.range_query_marker.publish(array)
    call_activate_objects( ids )
    return res

  def list_active_objects(self, msg):
      for key in self.objects.keys():
        active = active_objects[key]
        print 'ID    :', active.id
        print 'TYPE  :', active.object.description.type
        print 'NAME  :', active.object.name
        print 'ALIAS :', active.object.alias
        print 'POSE  :', active.object.pose
Ejemplo n.º 33
0
    def monitor(self):
        ''' This function starts the robucar_mon node and begin publishing
            the received data to robot_data using  RobotDataStamped msg'''

        pub = rospy.Publisher('robot_data', RobotDataStamped, queue_size=1)
        odom_pub = rospy.Publisher('odom', Odometry, queue_size=1)
        tf_broadcaster = TransformBroadcaster()
        odom = Odometry(
            header=rospy.Header(frame_id="odom"), child_frame_id='base_link')
        self.then = rospy.Time.now()

        while not rospy.is_shutdown():
            buf = self.conn.recv(struct.calcsize(self.ctrl_def))
            self.data = struct.unpack(self.ctrl_def, buf)
            self.now = rospy.Time.now()
            v = self.data[0]
            phi = radians(self.data[5])

            if (self.now - self.then).to_sec() < 0.095:
                pass
            else:
                dt = (self.now - self.then).to_sec()
                if self.mode == 0:
                    dx = v * cos(self.th)
                    dy = v * sin(self.th)
                    dth = (v / self.L) * tan(phi)
                elif self.mode == 1:
                    dx = v * cos(self.th + phi)
                    dy = v * sin(self.th + phi)
                    dth = (2 * v / self.L) * sin(phi)
                elif self.mode == 2:
                    dx = v * cos(self.th)
                    dy = v * sin(self.th)
                    dth = 0.0

                self.x += dx * dt
                self.y += dy * dt
                self.th += dth * dt

                quaternion = Quaternion(*quaternion_from_euler(0, 0, self.th))

                odom.header.stamp = self.now
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = dx
                odom.twist.twist.linear.y = dy
                odom.twist.twist.angular.z = dth

                self.stampedData.header.stamp = rospy.Time.now()
                self.stampedData.data.speed_average = self.data[0]
                self.stampedData.data.speed_FL = self.data[1]
                self.stampedData.data.speed_FR = self.data[2]
                self.stampedData.data.speed_RL = self.data[3]
                self.stampedData.data.speed_RR = self.data[4]
                self.stampedData.data.angle_forward = self.data[5]
                self.stampedData.data.angle_rear = self.data[6]
                self.stampedData.data.position_pan = self.data[7]
                self.stampedData.data.position_tilt = self.data[8]
                self.stampedData.data.speed_pan = self.data[9]
                self.stampedData.data.speed_tilt = self.data[10]

                pub.publish(self.stampedData)
                odom_pub.publish(odom)
                tf_broadcaster.sendTransform((self.x, self.y, 0),
                                             (quaternion.x, quaternion.y,
                                                 quaternion.z, quaternion.w),
                                             self.now,
                                             "base_link",
                                             "odom")

                # qfix = Quaternion(*quaternion_from_euler(0, 0, 0))
                # tf_broadcaster.sendTransform((0, 0, 0),
                #                              (qfix.x, qfix.y, qfix.z, qfix.w),
                #                              self.now,
                #                              "odom",
                #                              "map")

                self.then = self.now
Ejemplo n.º 34
0
class OMOR1miniNode:
    def __init__(self):
        self.ph = PacketHandler()
        self.ph.ser.reset_input_buffer()
        self.ph.ser.reset_output_buffer()
        self.ph.stop_periodic_comm()
        self.calc_yaw = ComplementaryFilter()

        self.max_lin_vel_x = 1.2
        self.max_ang_vel_z = 1.0

        self.ph.robot_state = {
            "VW": [0., 0.],
            "ODO": [0., 0.],
            "ACCL": [0., 0., 0.],
            "GYRO": [0., 0., 0.],
            "POSE": [0., 0.],
            "BAT": [0., 0., 0.],
        }

        self.ph.incomming_info = ['ODO', 'VW', "GYRO", "ACCL"]

        self.odom_pose = OdomPose()
        self.odom_vel = OdomVel()
        self.joint = Joint()

        self.gear_ratio = rospy.get_param("/motor_spec/gear_ratio") / 10.
        self.wheel_base = rospy.get_param("/motor_spec/wheel_base")
        self.wheel_radius = rospy.get_param("/motor_spec/wheel_radius")
        self.enc_pulse = rospy.get_param("/motor_spec/enc_pulse")
        self.use_gyro = rospy.get_param("/use_imu_during_odom_calc/use_imu")
        self.calc_yaw.filter_coef = rospy.get_param(
            "/use_imu_during_odom_calc/complementary_filter_coef")

        self.distance_per_pulse = 2 * math.pi * self.wheel_radius / self.enc_pulse / self.gear_ratio

        rospy.loginfo('Robot GEAR ratio: %s', self.gear_ratio)
        rospy.loginfo('Robot wheel_base: %s', self.wheel_base)
        rospy.loginfo('Robot wheel_radius: %s', self.wheel_radius)
        rospy.loginfo('Robot enc_pulse: %s', self.enc_pulse)
        rospy.loginfo('Robot distance_per_pulse: %s', self.distance_per_pulse)

        rospy.Service('battery_status', Battery, self.battery_service_handle)
        rospy.Service('set_led_color', Color, self.led_color_service_handle)
        rospy.Service('save_led_color', Color,
                      self.save_led_color_service_handle)
        rospy.Service('reset_odom', ResetOdom, self.reset_odom_handle)

        rospy.Subscriber("cmd_vel", Twist, self.sub_cmd_vel, queue_size=1)

        self.pub_joint_states = rospy.Publisher('joint_states',
                                                JointState,
                                                queue_size=10)
        self.odom_pub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.odom_broadcaster = TransformBroadcaster()

        self.ph.update_battery_state()
        self.ph.set_periodic_info()

        sleep(0.1)

        self.ph.set_periodic_info()

        rospy.loginfo('==> Start R1mini ')
        rospy.Timer(rospy.Duration(0.01), self.update_robot)
        self.odom_pose.timestamp = rospy.Time.now()
        self.odom_pose.pre_timestamp = rospy.Time.now()

    def convert2odo_from_each_wheel(self, enc_l, enc_r):
        return enc_l * self.distance_per_pulse, enc_r * self.distance_per_pulse

    def update_odometry(self, odo_l, odo_r, trans_vel, orient_vel, vel_z):
        odo_l /= 1000.
        odo_r /= 1000.
        trans_vel /= 1000.
        orient_vel /= 1000.

        self.odom_pose.timestamp = rospy.Time.now()
        dt = (self.odom_pose.timestamp - self.odom_pose.pre_timestamp).to_sec()
        self.odom_pose.pre_timestamp = self.odom_pose.timestamp

        if self.use_gyro:
            self.calc_yaw.wheel_ang += orient_vel * dt
            self.odom_pose.theta = self.calc_yaw.calc_filter(
                vel_z * math.pi / 180., dt)
            rospy.loginfo(
                'R1mini state : whl pos %1.2f, %1.2f, gyro : %1.2f, whl odom : %1.2f, robot theta : %1.2f',
                odo_l, odo_r, vel_z, self.calc_yaw.wheel_ang * 180 / math.pi,
                self.odom_pose.theta * 180 / math.pi)
        else:
            self.odom_pose.theta += orient_vel * dt
            rospy.loginfo('R1mini state : wheel pos %s, %s, speed %s, %s',
                          odo_l, odo_r, trans_vel, orient_vel)

        d_x = trans_vel * math.cos(self.odom_pose.theta)
        d_y = trans_vel * math.sin(self.odom_pose.theta)

        self.odom_pose.x += d_x * dt
        self.odom_pose.y += d_y * dt

        odom_orientation_quat = quaternion_from_euler(0, 0,
                                                      self.odom_pose.theta)

        self.odom_vel.x = trans_vel
        self.odom_vel.y = 0.
        self.odom_vel.w = orient_vel

        odom = Odometry()
        odom.header.frame_id = "odom"
        odom.child_frame_id = "base_footprint"

        self.odom_broadcaster.sendTransform(
            (self.odom_pose.x, self.odom_pose.y, 0.), odom_orientation_quat,
            self.odom_pose.timestamp, odom.child_frame_id,
            odom.header.frame_id)

        odom.header.stamp = rospy.Time.now()
        odom.pose.pose = Pose(Point(self.odom_pose.x, self.odom_pose.y, 0.),
                              Quaternion(*odom_orientation_quat))
        odom.twist.twist = Twist(Vector3(self.odom_vel.x, self.odom_vel.y, 0),
                                 Vector3(0, 0, self.odom_vel.w))

        self.odom_pub.publish(odom)

    def updateJointStates(self, odo_l, odo_r, trans_vel, orient_vel):
        odo_l /= 1000.
        odo_r /= 1000.

        wheel_ang_left = odo_l / self.wheel_radius
        wheel_ang_right = odo_r / self.wheel_radius

        wheel_ang_vel_left = (
            trans_vel -
            (self.wheel_base / 2.0) * orient_vel) / self.wheel_radius
        wheel_ang_vel_right = (
            trans_vel +
            (self.wheel_base / 2.0) * orient_vel) / self.wheel_radius

        self.joint.joint_pos = [wheel_ang_left, wheel_ang_right]
        self.joint.joint_vel = [wheel_ang_vel_left, wheel_ang_vel_right]

        joint_states = JointState()
        joint_states.header.frame_id = "base_link"
        joint_states.header.stamp = rospy.Time.now()
        joint_states.name = self.joint.joint_name
        joint_states.position = self.joint.joint_pos
        joint_states.velocity = self.joint.joint_vel
        joint_states.effort = []

        self.pub_joint_states.publish(joint_states)

    def update_robot(self, event):
        raw_data = self.ph.parser()

        try:
            [trans_vel, orient_vel] = self.ph.robot_state['VW']
            [odo_l, odo_r] = self.ph.robot_state['ODO']
            [vel_x, vel_y, vel_z] = self.ph.robot_state['GYRO']
            [acc_x, acc_y, acc_z] = self.ph.robot_state['ACCL']

            self.update_odometry(odo_l, odo_r, trans_vel, orient_vel, vel_z)
            self.updateJointStates(odo_l, odo_r, trans_vel, orient_vel)

        except ValueError:
            rospy.logwarn(
                "ValueError occupied during read robot status in update_robot state. \n\r Raw_data : %s",
                raw_data)

    def sub_cmd_vel(self, cmd_vel_msg):
        lin_vel_x = cmd_vel_msg.linear.x
        ang_vel_z = cmd_vel_msg.angular.z

        lin_vel_x = max(-self.max_lin_vel_x, min(self.max_lin_vel_x,
                                                 lin_vel_x))
        ang_vel_z = max(-self.max_ang_vel_z, min(self.max_ang_vel_z,
                                                 ang_vel_z))

        self.ph.set_wheel_velocity(lin_vel_x * 1000, ang_vel_z * 1000)

    def battery_service_handle(self, req):
        self.ph.update_battery_state()

        bat_status = self.ph.robot_state['BAT']
        if len(bat_status) == 3:
            volt = bat_status[0] * 0.1
            SOC = bat_status[1]
            current = bat_status[2] * 0.001
            return BatteryResponse(volt, SOC, current)
        else:
            rospy.logwarn("Battery Status is not correct.")

    def led_color_service_handle(self, req):
        command = "$cCOLOR," + str(req.red) + ',' + str(req.green) + ',' + str(
            req.blue)
        self.ph.write_port(command)
        return ColorResponse()

    def save_led_color_service_handle(self, req):
        command = "$sCOLOR," + str(req.red) + ',' + str(req.green) + ',' + str(
            req.blue)
        self.ph.write_port(command)
        return ColorResponse()

    def reset_odom_handle(self, req):
        self.odom_pose.x = req.x
        self.odom_pose.y = req.y
        self.odom_pose.theta = req.theta

        return ResetOdomResponse()

    def main(self):
        rospy.spin()
Ejemplo n.º 35
0
class base_controller(Thread):
    """ Controller to handle movement & odometry feedback for a differential drive mobile base. """
    def __init__(self, Serializer, name):
        Thread.__init__ (self)
        self.finished = Event()
        
        # Handle for the Serializer
        self.mySerializer = Serializer

        # Parameters
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        self.ticks_per_meter = float(self.mySerializer.ticks_per_meter)
        self.wheel_track = self.mySerializer.wheel_track
        self.gear_reduction = self.mySerializer.gear_reduction
        self.encoder_resolution = self.mySerializer.encoder_resolution
        
        now = rospy.Time.now()
        
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = now + self.t_delta
        self.then = now # time for determining dx/dy

        # internal data        
        self.enc_left = 0            # encoder readings
        self.enc_right = 0
        self.x = 0.                  # position in xy plane
        self.y = 0.
        self.th = 0.                 # rotation in radians
        self.encoder_error = False

        # subscriptions
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)
        
        # Clear any old odometry info
        self.mySerializer.clear_encoder([1, 2])
        
        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry)
        self.odomBroadcaster = TransformBroadcaster()
        
        rospy.loginfo("Started Base Controller '"+ name +"' for a base of " + str(self.wheel_track) + "m wide with " + str(self.ticks_per_meter) + " ticks per meter")

    def run(self):
        rosRate = rospy.Rate(self.rate)
        rospy.loginfo("Publishing Odometry data at: " + str(self.rate) + " Hz")
        
        old_left = old_right = 0
        bad_encoder_count = 0
        
        while not rospy.is_shutdown() and not self.finished.isSet():
            now = rospy.Time.now()         
            if now > self.t_next:
                dt = now - self.then
                self.then = now
                dt = dt.to_sec()
                
                # read encoders
                try:
                    left, right = self.mySerializer.get_encoder_count([1, 2])
                except:
                    self.encoder_error = True
                    rospy.loginfo("Could not read encoders: " + str(bad_encoder_count))
                    bad_encoder_count += 1
                    rospy.loginfo("Encoder counts at exception: " + str(left) + ", " + str(right)) 
                    continue
                
                if self.encoder_error:
                    self.enc_left = left
                    self.enc_right = right
                    self.encoder_error = False
                    continue
                
                # calculate odometry
                dleft = (left - self.enc_left) / self.ticks_per_meter
                dright = (right - self.enc_right) / self.ticks_per_meter
                
                self.enc_left = left
                self.enc_right = right
                
                dxy_ave = (dleft + dright) / 2.0
                dth = (dright - dleft) / self.wheel_track
                vxy = dxy_ave / dt
                vth = dth / dt
    
                if (dxy_ave != 0):
                    dx = cos(dth) * dxy_ave
                    dy = -sin(dth) * dxy_ave
                    self.x += (cos(self.th) * dx - sin(self.th) * dy)
                    self.y += (sin(self.th) * dx + cos(self.th) * dy)
    
                if (dth != 0):
                    self.th += dth 
    
                quaternion = Quaternion()
                quaternion.x = 0.0 
                quaternion.y = 0.0
                quaternion.z = sin(self.th / 2.0)
                quaternion.w = cos(self.th / 2.0)
    
                # Create the odometry transform frame broadcaster.
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0), 
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(),
                    "base_link",
                    "odom"
                    )
    
                odom = Odometry()
                odom.header.frame_id = "odom"
                odom.child_frame_id = "base_link"
                odom.header.stamp = now
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = vxy
                odom.twist.twist.linear.y = 0
                odom.twist.twist.angular.z = vth
    
                self.odomPub.publish(odom)
                
                self.t_next = now + self.t_delta
                
            rosRate.sleep()


    def cmdVelCallback(self, req):
        """ Handle velocity-based movement requests. """
        x = req.linear.x         # m/s
        th = req.angular.z       # rad/s

        if x == 0:
            # Turn in place
            right = th * self.wheel_track  * self.gear_reduction / 2.0
            left = -right
        elif th == 0:   
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track  * self.gear_reduction / 2.0
            right = x + th * self.wheel_track  * self.gear_reduction / 2.0

        # Set motor speeds in meters per second.
        self.mySerializer.mogo_m_per_s([1, 2], [left, right])
        
    def stop(self):
        print "Shutting down base controller"
        self.finished.set()
        self.join()
Ejemplo n.º 36
0
class DiffTf:
    #############################################################################

    #############################################################################
    def __init__(self):
        #############################################################################
        rospy.init_node("diff_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)

        #### parameters #######
        self.rate = rospy.get_param(
            '~rate', 10)  # the rate at which to publish the transform
        self.base_width = float(rospy.get_param(
            '~base_width', 0.245))  # The wheel base width in meters

        self.base_frame_id = rospy.get_param(
            '~base_frame_id',
            'base_link')  # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param(
            '~odom_frame_id',
            'odom')  # the name of the odometry reference frame

        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param(
            'wheel_low_wrap',
            (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min)
        self.encoder_high_wrap = rospy.get_param(
            'wheel_high_wrap',
            (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min)

        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        self.dx = 0  # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()
        self.v_left = 0
        self.v_right = 0
        self.d_left = 0
        self.d_right = 0
        self.v_left_update = False
        self.v_right_update = False
        self.d_left_update = False
        self.d_right_update = False
        # subscriptions
        rospy.Subscriber("lwheel_vel", Float32, self.lwheelCallback)
        rospy.Subscriber("rwheel_vel", Float32, self.rwheelCallback)
        rospy.Subscriber("lwheel_distance", Float32, self.lwheeldCallback)
        rospy.Subscriber("rwheel_distance", Float32, self.rwheeldCallback)

        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()

    def lwheeldCallback(self, msg):
        self.d_left_update = True
        self.d_left = msg.data

    def rwheeldCallback(self, msg):
        self.d_right_update = True
        self.d_right = msg.data

    #############################################################################
    def spin(self):
        #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    #############################################################################
    def update(self):
        #############################################################################
        now = rospy.Time.now()
        if self.d_left_update and self.d_right_update and self.v_left_update and self.v_right_update:
            # distance traveled is the average of the two wheels
            d = (self.d_left + self.d_right) / 2
            # this approximation works (in radians) for small angles
            th = (self.d_right - self.d_left) / self.base_width
            # calculate velocities
            self.dx = (self.v_left + self.v_right) / 2
            self.dr = (self.v_left - self.v_right) / self.base_width

            if (d != 0):
                # calculate distance traveled in x and y
                x = cos(th) * d
                y = -sin(th) * d
                # calculate the final position of the robot
                self.x = self.x + (cos(self.th) * x - sin(self.th) * y)
                self.y = self.y + (sin(self.th) * x + cos(self.th) * y)
            if (th != 0):
                self.th = self.th + th

            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2)
            quaternion.w = cos(self.th / 2)
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(), self.base_frame_id, self.odom_frame_id)

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)
            self.v_left_update = True
            self.v_right_update = True
            self.d_left_update = True
            self.d_right_update = True

    #############################################################################
    def lwheelCallback(self, msg):
        #############################################################################
        # update left wheel velocity
        self.v_left_update = True
        self.v_left = msg.data

    #############################################################################
    def rwheelCallback(self, msg):
        #############################################################################
        # update right wheel velocity
        self.v_right_update = True
        self.v_right = msg.data
Ejemplo n.º 37
0
class HueyNode:
    def __init__(self):
        """ Start up connection to the Huey Robot. """
        rospy.init_node('neato')

        self.CMD_RATE =2 
        self.newTwistCmd = 0

        self.telnet_ip = rospy.get_param('~telnet_ip', "Huey-Tiger")
        rospy.loginfo("Using telnet: %s" % self.telnet_ip)

        self.robot = Huey(self.telnet_ip)

        #rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('base_scan', LaserScan, queue_size=10)
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.buttonPub = rospy.Publisher('button', Button, queue_size=10)
        self.sensorPub = rospy.Publisher('sensor', Sensor, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        #self.cmd_vel = [0, 0]
        #self.old_vel = self.cmd_vel

    def spin(self):
        encoders = [0, 0]

        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0
        then = rospy.Time.now()

        #rospy.loginfo("spin: before LaserScan")

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id', 'base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link))

        scan.angle_min =0.0 
        scan.angle_max =359.0*pi/180.0 
        scan.angle_increment =pi/180.0 
        scan.range_min = 0.020
        scan.range_max = 5.0

        #rospy.loginfo("spin: before Odometry")
        odom = Odometry(header=rospy.Header(frame_id="odom"), child_frame_id='base_footprint')

        button = Button()
        sensor = Sensor()

        # main loop of driver
        r = rospy.Rate(2)
        cmd_rate= self.CMD_RATE

        rospy.loginfo(">>> spin: before while loop <<<")

        while not rospy.is_shutdown():
            left, right = self.robot.getMotors()

            # prepare laser scan
            scan.header.stamp = rospy.Time.now()

            self.robot.requestScan()
            #rospy.loginfo("spin: loop: requestScan")
            scan.ranges = self.robot.getLdsScan()
            #if len(scan.ranges) == 0:
            #    scan.ranges = self.robot.getLdsScan()

            # now update position information
            dt = (scan.header.stamp - then).to_sec()
            then = scan.header.stamp

            d_left =  (left - encoders[0])/1000.0
            d_right =  (right - encoders[1])/1000.0
            encoders = [left, right]

            #print d_left, d_right, encoders

            dx = (d_left+d_right)/2
            dth = (d_right-d_left)/(self.robot.base_width/1000.0)

            x = cos(dth)*dx
            y = -sin(dth)*dx
            self.x += cos(self.th)*x - sin(self.th)*y
            self.y += sin(self.th)*x + cos(self.th)*y
            self.th += dth
            #print self.x,self.y,self.th

            # prepare tf from base_link to odom
            quaternion = Quaternion()
            quaternion.z = sin(self.th/2.0)
            quaternion.w = cos(self.th/2.0)

            # prepare odometry
            odom.header.stamp = rospy.Time.now()
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = dx/dt
            odom.twist.twist.angular.z = dth/dt


            # sensors
            lsb, rsb, lfb, rfb = self.robot.getDigitalSensors()
            #rospy.loginfo("spin: loop: getDigitalSensors")

            # buttons
            btn_soft, btn_scr_up, btn_start, btn_back, btn_scr_down = self.robot.getButtons()


            # publish everything
            self.odomBroadcaster.sendTransform((self.x, self.y, 0), (quaternion.x, quaternion.y, quaternion.z,
                                                                     quaternion.w), then, "base_footprint", "odom")
            #rospy.loginfo("spin: loop: sendTransform")
            if len(scan.ranges) > 0:
                self.scanPub.publish(scan)

            self.odomPub.publish(odom)
            button_enum = ("Soft_Button", "Up_Button", "Start_Button", "Back_Button", "Down_Button")
            sensor_enum = ("Left_Side_Bumper", "Right_Side_Bumper", "Left_Bumper", "Right_Bumper")
            for idx, b in enumerate((btn_soft, btn_scr_up, btn_start, btn_back, btn_scr_down)):
                if b == 1:
                    button.value = b
                    button.name = button_enum[idx]
                    self.buttonPub.publish(button)

            for idx, b in enumerate((lsb, rsb, lfb, rfb)):
                if b == 1:
                    sensor.value = b
                    sensor.name = sensor_enum[idx]
                    self.sensorPub.publish(sensor)
            # wait, then do it again
            #rospy.loginfo("spin: loop: before sleep()")
            r.sleep()
            # Steve: testing with longer sleep 
            #time.sleep(1)

        # shut down
        rospy.loginfo(">>>>>> Exiting <<<<<<<<")
class OdometryNode:
    def __init__(self):
        self.odometry = odometry.Odometry()

    def main(self):
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.tfPub = TransformBroadcaster()

        rospy.init_node('diff_drive_odometry')
        self.nodeName = rospy.get_name()
        rospy.loginfo("{0} started".format(self.nodeName))

        rospy.Subscriber("lwheel_ticks", Int32, self.leftCallback)
        rospy.Subscriber("rwheel_ticks", Int32, self.rightCallback)
        rospy.Subscriber("initialpose", PoseWithCovarianceStamped,
                         self.on_initial_pose)

        self.ticksPerMeter = int(rospy.get_param('~ticks_per_meter'))
        self.wheelSeparation = float(rospy.get_param('~wheel_separation'))
        self.rate = float(rospy.get_param('~rate', 10.0))
        self.baseFrameID = rospy.get_param('~base_frame_id', 'base_link')
        self.odomFrameID = rospy.get_param('~odom_frame_id', 'odom')
        self.encoderMin = int(rospy.get_param('~encoder_min', -32768))
        self.encoderMax = int(rospy.get_param('~encoder_max', 32767))

        self.odometry.setWheelSeparation(self.wheelSeparation)
        self.odometry.setTicksPerMeter(self.ticksPerMeter)
        self.odometry.setEncoderRange(self.encoderMin, self.encoderMax)
        self.odometry.setTime(rospy.get_time())

        rate = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.publish()
            rate.sleep()

    def publish(self):
        self.odometry.updatePose(rospy.get_time())
        now = rospy.get_rostime()
        pose = self.odometry.getPose()

        q = quaternion_from_euler(0, 0, pose.theta)
        self.tfPub.sendTransform((pose.x, pose.y, 0), (q[0], q[1], q[2], q[3]),
                                 now, self.baseFrameID, self.odomFrameID)

        odom = Odometry()
        odom.header.stamp = now
        odom.header.frame_id = self.odomFrameID
        odom.child_frame_id = self.baseFrameID
        odom.pose.pose.position.x = pose.x
        odom.pose.pose.position.y = pose.y
        odom.pose.pose.orientation.x = q[0]
        odom.pose.pose.orientation.y = q[1]
        odom.pose.pose.orientation.z = q[2]
        odom.pose.pose.orientation.w = q[3]
        odom.twist.twist.linear.x = pose.xVel
        odom.twist.twist.angular.z = pose.thetaVel
        self.odomPub.publish(odom)

    def on_initial_pose(self, msg):
        q = [
            msg.pose.pose.orientation.x, msg.pose.pose.orientation.x,
            msg.pose.pose.orientation.x, msg.pose.pose.orientation.w
        ]
        roll, pitch, yaw = euler_from_quaternion(q)

        pose = Pose()
        pose.x = msg.pose.pose.position.x
        pose.y = msg.pose.pose.position.y
        pose.theta = yaw

        rospy.loginfo('Setting initial pose to %s', pose)
        self.odometry.setPose(pose)

    def leftCallback(self, msg):
        self.odometry.updateLeftWheel(msg.data)

    def rightCallback(self, msg):
        self.odometry.updateRightWheel(msg.data)
Ejemplo n.º 39
0
class ThymioDriver():
	# ======== class initialization ======== 
	def __init__(self):
		rospy.init_node('thymio')
		# initialize parameters
		self.x = 0
		self.y = 0
		self.th = 0
		self.then = rospy.Time.now()
		self.odom = Odometry(header=rospy.Header(frame_id='odom'),child_frame_id='base_link')
		
		# load script on the Thymio
		rospy.wait_for_service('/aseba/load_script')
		load_script = rospy.ServiceProxy('/aseba/load_script',LoadScripts)
		script_filename = roslib.packages.get_pkg_dir('thymio_navigation_driver') + '/aseba/thymio_ros.aesl'
		load_script(script_filename)
		
		# subscribe to topics
		rospy.Subscriber("cmd_vel", Twist, self.on_cmd_vel)
		rospy.Subscriber('/aseba/events/odometry', AsebaEvent, self.on_aseba_odometry_event)
		self.aseba_pub = rospy.Publisher('/aseba/events/set_speed', AsebaEvent)
		self.odom_pub = rospy.Publisher('odom',Odometry)
		self.odom_broadcaster = TransformBroadcaster()
	
	# ======== we send the speed to the aseba running on the robot  ======== 
	def set_speed(self,values):
		self.aseba_pub.publish(AsebaEvent(rospy.get_rostime(),0,values))
	
	# ======== stop the robot safely ======== 
	def shutdown(self):
		self.set_speed([0,0])
	
	# ======== processing odometry events received from the robot ======== 
	def on_aseba_odometry_event(self,data): 
		now = data.stamp
		dt = (now-self.then).to_sec()
		self.then = now
		dsl = (data.data[0]*dt)/SPEED_COEF # left wheel delta in mm
		dsr = (data.data[1]*dt)/SPEED_COEF # right wheel delta in mm
		ds = ((dsl+dsr)/2.0)/1000.0      # robot traveled distance in meters
		dth = atan2(dsr-dsl,BASE_WIDTH)  # turn angle

		self.x += ds*cos(self.th+dth/2.0)
		self.y += ds*sin(self.th+dth/2.0)
		self.th+= dth

		# prepare tf from base_link to odom 
		quaternion = Quaternion()
		quaternion.z = sin(self.th/2.0)
		quaternion.w = cos(self.th/2.0)

		# prepare odometry
		self.odom.header.stamp = rospy.Time.now() # OR TO TAKE ONE FROM THE EVENT?
		self.odom.pose.pose.position.x = self.x
		self.odom.pose.pose.position.y = self.y
		self.odom.pose.pose.position.z = 0
		self.odom.pose.pose.orientation = quaternion
		self.odom.twist.twist.linear.x = ds/dt
		self.odom.twist.twist.angular.z = dth/dt

		# publish odometry
		self.odom_broadcaster.sendTransform((self.x,self.y,0),(quaternion.x,quaternion.y,quaternion.z,quaternion.w),self.then,"base_link","odom")
		self.odom_pub.publish(self.odom)
	
	# ======== processing events received from the robot  ======== 
	def on_cmd_vel(self,data):
		x = data.linear.x * 1000.0 # from meters to millimeters 
		x = x * SPEED_COEF # to thymio units
		th = data.angular.z * (BASE_WIDTH/2) # in mm
		th = th * SPEED_COEF # in thymio units
		k = max(abs(x-th),abs(x+th))
		# sending commands higher than max speed will fail
		if k > MAX_SPEED:
			x = x*MAX_SPEED/k; th = th*MAX_SPEED/k
		self.set_speed([int(x-th),int(x+th)])

	# ======== ======== ======== ======== ======== ======== ========      
	def control_loop(self):	
		rospy.on_shutdown(self.shutdown) # on shutdown hook
		while not rospy.is_shutdown():
			rospy.spin()
Ejemplo n.º 40
0
class BoardController():
    """
    Main board controller
    """

    # List of commands and argument formats
    commands = [["cmd_set_motor_params", "ffff"],
                ["cmd_set_cps_pid_params", "fff"], ["cmd_set_motor_pwm", "ii"],
                ["cmd_get_motor_pwm", ""], ["cmd_ret_motor_pwm", "ii"],
                ["cmd_get_encoder_ticks", ""], ["cmd_ret_encoder_ticks", "ll"],
                ["cmd_set_motor_cps", "ff"], ["cmd_get_motor_cps", ""],
                ["cmd_ret_motor_cps", "ff"], ["cmd_get_odometry", ""],
                ["cmd_ret_odometry", "fff"], ["cmd_reset_system", ""],
                ["cmd_ret_line", "s"]]

    def __init__(self, motor_cpr, wheel_radius, wheel_distance, max_linear_vel,
                 max_angular_vel, odom_rate, base_frame, odom_frame):
        """
        Input:
            motor_cpr:
                motor encoder counts per revolution (4x resolution)
            wheel_radius:
                radius of the robot wheels (meters)
            wheel_distance:
                distance between robot wheels (meters)
            max_linear_vel:
                maximun speed of the robot (m/s)
            max_angular_vel:
                maximun angular speed of the robot (rad/s)
            odom_rate:
                publishing rate of robot odometry
            base_frame:
                robot base frame name
            odom_frame:
                odometry frame name
        """

        self.motor_cpr = motor_cpr
        self.wheel_radius = wheel_radius
        self.wheel_distance = wheel_distance
        self.max_linear_vel = max_linear_vel
        self.max_angular_vel = max_angular_vel
        self.odom_rate = odom_rate
        self.base_frame = base_frame
        self.odom_frame = odom_frame

        # Initialize ArduinoBoard instance
        self.port = self.getBoardUSBPort(self._DEFAULT_PORT_PREFIX)
        if len(self.port) == 0:
            rospy.logfatal("Not founded any ttyACM port. Exiting...")
            exit()

        rospy.loginfo("Connecting to port %s..." % self.port[0])

        # Arduino Zero >> int 4 bytes
        self.board = PyCmdMessenger.ArduinoBoard(self.port[0],
                                                 self._DEFAULT_BAUD_RATE,
                                                 int_bytes=4)

        # Initialize the messenger
        self.cmd = PyCmdMessenger.CmdMessenger(self.board,
                                               BoardController.commands)

        rospy.loginfo("done. Connecction to serial port %s established" %
                      self.port[0])

        # Reset board
        rospy.loginfo("Resetting board counters")
        self.cmd.send("cmd_reset_system")

        # ROS Node Subscriber
        self.sub_cmd_vel = rospy.Subscriber('cmd_vel',
                                            Twist,
                                            self.compute_motor_velocities_cb,
                                            queue_size=1)
        # Odometry publisher
        self.odom_pub = rospy.Publisher("odom", Odometry, queue_size=10)
        self.odom_broadcaster = TransformBroadcaster()
        rospy.Timer(rospy.Duration(1.0 / self.odom_rate), self.update_odometry)

    def getBoardUSBPort(self, port_prefix):
        # Try to find the associated USB COM port
        comports = [tuple(p) for p in list(serial.tools.list_ports.comports())]

        # List of ports containing port_prefix
        port = [port[0] for port in comports if port_prefix in port[0]]

        return port

    def compute_motor_velocities_cb(self, twist_msg):
        """
        Gets /cmd_vel values and compute the appropriate motor velocities 
        in c.p.s. to send to the robot base
        
        Vr = (2*linear_vel + angular_vel*wheel_distance)/2*wheel_radius
        Vl = (2*linear_vel - angular_vel*wheel_distance)/2*wheel_radius
        """
        linear_vel = twist_msg.linear.x
        angular_vel = twist_msg.angular.z

        # Right and Left motor velocities in rad/s
        v2 = 2 * linear_vel
        r2 = 2 * self.wheel_radius
        wL = angular_vel * self.wheel_distance

        vr = (v2 - wL) / r2
        vl = (v2 + wL) / r2

        # Compute velocities in c.p.s
        rads_to_counts = self.motor_cpr / (2 * math.pi)
        vr *= rads_to_counts
        vl *= rads_to_counts

        # Send Command
        #rospy.loginfo("vr: %f    vl: %f" % (vr,vl))
        self.cmd.send("cmd_set_motor_cps", vr, vl)

    def update_odometry(self, event):
        """
        Gets the current odometry from the robot and publish the ROS transform
        
        """
        # send command
        self.cmd.send("cmd_get_odometry")

        # receive response from Arduino
        data = self.cmd.receive()
        x = data[1][0]
        y = data[1][1]
        theta = data[1][2]
        now = rospy.Time.now()

        # publish the odom information
        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = math.sin(theta / 2)
        quaternion.w = math.cos(theta / 2)
        self.odom_broadcaster.sendTransform(
            (x, y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w), now,
            self.base_frame, self.odom_frame)

        odom = Odometry()
        odom.header.stamp = now
        odom.header.frame_id = self.odom_frame
        odom.pose.pose.position.x = x
        odom.pose.pose.position.y = y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        odom.child_frame_id = self.base_frame
        odom.twist.twist.linear.x = 0  # linear velocity
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = 0  # angular velocity
        self.odom_pub.publish(odom)
Ejemplo n.º 41
0
class TFMarkerServer(object):
    """TFMarkerServer"""
    def __init__(self, rate = 30.0, filename = None):
        # Marker server
        self.server = InteractiveMarkerServer('camera_marker')
        # TF broadcaster
        self.tf = TransformBroadcaster()

        # Marker pose
        self.pose_mutex = Lock()
        self.marker_position = (0.0, 0.0, 0.0)
        self.marker_orientation = (0.0, 0.0, 0.0, 1.0)

        # Load init position
        self.filename = filename
        if self.filename:
            with open(self.filename, 'r') as stream:
                init_data = yaml.load(stream)['init_position']
                self.marker_position = (init_data['x'], init_data['y'], init_data['z'])
                self.marker_orientation = (0.0, 0.0, 0.0, 1.0)

        # Register shutdown callback
        rospy.on_shutdown(self.shutdown) 

        # Add marker
        self.add_6DOF()

        # Timer for TF broadcaster
        rospy.Timer(rospy.Duration(1.0/rate), self.publish_transform)


    def add_6DOF(self, init_position = Point( 0.0, 0.0, 0.0), frame_id = 'map'):
        marker = InteractiveMarker()
        marker.header.frame_id = frame_id
        marker.pose.position = init_position
        marker.scale = 0.3

        marker.name = 'camera_marker'
        marker.description = 'Camera 6-DOF pose control'

        # X axis rotation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 1
        control.orientation.y = 0
        control.orientation.z = 0
        control.name = "rotate_x"
        control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
        marker.controls.append(control)
        # X axis traslation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 1
        control.orientation.y = 0
        control.orientation.z = 0
        control.name = "move_x"
        control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
        marker.controls.append(control)
        # Y axis rotation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 0
        control.orientation.y = 1
        control.orientation.z = 0
        control.name = "rotate_y"
        control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
        marker.controls.append(control)
        # Y axis traslation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 0
        control.orientation.y = 1
        control.orientation.z = 0
        control.name = "move_y"
        control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
        marker.controls.append(control)
        # Z axis rotation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 0
        control.orientation.y = 0
        control.orientation.z = 1
        control.name = "rotate_z"
        control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS
        marker.controls.append(control)
        # Z axis traslation
        control = InteractiveMarkerControl()
        control.orientation.w = 1
        control.orientation.x = 0
        control.orientation.y = 0
        control.orientation.z = 1
        control.name = "move_z"
        control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS
        marker.controls.append(control)
        # Add marker to server
        self.server.insert(marker, self.marker_feedback)
        self.server.applyChanges()

    def publish_transform(self, timer_event):
        time = rospy.Time.now()
        self.pose_mutex.acquire()
        self.tf.sendTransform(self.marker_position, self.marker_orientation,
            time, 'sensor_base', 'map')
        self.pose_mutex.release()

    def marker_feedback(self, feedback):
        rospy.loginfo('Feedback from ' + feedback.marker_name)
        # Check event
        if feedback.event_type == InteractiveMarkerFeedback.POSE_UPDATE:
            rospy.loginfo( 'Pose changed')
            # Update marker position
            self.pose_mutex.acquire()
            self.marker_position = (feedback.pose.position.x,
                feedback.pose.position.y, feedback.pose.position.z)
            # Update marker orientation
            self.marker_orientation = (feedback.pose.orientation.x,
                feedback.pose.orientation.y, feedback.pose.orientation.z,
                feedback.pose.orientation.w)
            self.pose_mutex.release()

    def shutdown(self):
        data = {
            'init_position' :
            {
                'x': 0.0,
                'y': 0.0,
                'z': 0.0,
                'roll': 0.0,
                'pitch': 0.0,
                'yaw': 0.0,
            }

        }
        rospy.loginfo('Writing current position')
        with open(self.filename, 'w') as outfile:
            outfile.write(yaml.dump(data, default_flow_style=True))
Ejemplo n.º 42
0
class base_controller(Thread):
    """ Controller to handle movement & odometry feedback for a differential drive mobile base. """
    def __init__(self, name):
        Thread.__init__ (self)
        self.finished = Event()

        # Parameters
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        now = rospy.Time.now()
        
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = now + self.t_delta
        self.then = now # time for determining dx/dy

        # internal data        
        self.x = 0.                  # position in xy plane
        self.y = 0.
        self.th = 0.                 # rotation in radians

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry)
        self.odomBroadcaster = TransformBroadcaster()
        
        rospy.loginfo("Started Odometry simmulator " + name )

    def run(self):
        rosRate = rospy.Rate(self.rate)
        rospy.loginfo("Publishing Odometry data at: " + str(self.rate) + " Hz")

        vx = 0.0
        vy = 0.0
        vth = 0.0

        while not rospy.is_shutdown() and not self.finished.isSet():
            now = rospy.Time.now()         
            if now > self.t_next:
                dt = now - self.then
                self.then = now
                dt = dt.to_sec()

                delta_x = (vx * cos(self.th) - vy * sin(self.th)) * dt
                delta_y = (vx * sin(self.th) + vy * cos(self.th)) * dt
                delta_th = vth * dt

                self.x += delta_x
                self.y += delta_y
                self.th += delta_th


                quaternion = Quaternion()
                quaternion.x = 0.0 
                quaternion.y = 0.0
                quaternion.z = sin(self.th / 2.0)
                quaternion.w = cos(self.th / 2.0)
    
                # Create the odometry transform frame broadcaster.
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0), 
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(),
                    "base_link",
                    "odom"
                    )
    
                odom = Odometry()
                odom.header.frame_id = "odom"
                odom.child_frame_id = "base_link"
                odom.header.stamp = now
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = vx
                odom.twist.twist.linear.y = 0
                odom.twist.twist.angular.z = vth
    
                self.odomPub.publish(odom)
                
                self.t_next = now + self.t_delta
                
            rosRate.sleep()

    def stop(self):
        print "Shutting down base odom_sim"
        self.finished.set()
        self.join()
Ejemplo n.º 43
0
class NeatoNode:

    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        self.port = rospy.get_param('~port', "/dev/ttyACM0")
        rospy.loginfo("Using port: %s"%(self.port))

        self.robot = xv11(self.port)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('base_scan', LaserScan)
        self.odomPub = rospy.Publisher('odom',Odometry)
        self.dropPub = rospy.Publisher('neato_drop',NeatoDropSensor)
        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_vel = [0,0] 

    def spin(self):        
        encoders = [0,0]

        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0
        then = rospy.Time.now()

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id','base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link)) 
        scan.angle_min = 0
        scan.angle_max = 6.26
        scan.angle_increment = 0.017437326
        scan.range_min = 0.020
        scan.range_max = 5.0
        odom = Odometry(header=rospy.Header(frame_id="odom"), child_frame_id='base_link')
    
        # main loop of driver
        r = rospy.Rate(5)
        self.robot.requestScan()
        while not rospy.is_shutdown():
            # prepare laser scan
            scan.header.stamp = rospy.Time.now()    
            #self.robot.requestScan()
            scan.ranges = self.robot.getScanRanges()

            # get motor encoder values
            left, right = self.robot.getMotors()
            
            # get analog sensors
            self.robot.getAnalogSensors()
            
            # get drop sensors
            left_drop = self.robot.state["LeftDropInMM"]
            right_drop = self.robot.state["RightDropInMM"]

            # send updated movement commands
            self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1], max(abs(self.cmd_vel[0]),abs(self.cmd_vel[1])))
            
            # ask for the next scan while we finish processing stuff
            self.robot.requestScan()
            
            # now update position information
            dt = (scan.header.stamp - then).to_sec()
            then = scan.header.stamp

            d_left = (left - encoders[0])/1000.0
            d_right = (right - encoders[1])/1000.0
            encoders = [left, right]
            
            dx = (d_left+d_right)/2
            dth = (d_right-d_left)/(BASE_WIDTH/1000.0)

            x = cos(dth)*dx
            y = -sin(dth)*dx
            self.x += cos(self.th)*x - sin(self.th)*y
            self.y += sin(self.th)*x + cos(self.th)*y
            self.th += dth

            # prepare tf from base_link to odom
            quaternion = Quaternion()
            quaternion.z = sin(self.th/2.0)
            quaternion.w = cos(self.th/2.0)

            # prepare odometry
            odom.header.stamp = rospy.Time.now()
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = dx/dt
            odom.twist.twist.angular.z = dth/dt
            
            # prepare drop
            drop = NeatoDropSensor()
            drop.header.stamp = rospy.Time.now()
            drop.left = left_drop
            drop.right = right_drop

            # publish everything
            self.odomBroadcaster.sendTransform( (self.x, self.y, 0), (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                then, "base_link", "odom" )
            self.scanPub.publish(scan)
            self.odomPub.publish(odom)
            self.dropPub.publish(drop)

            # wait, then do it again
            r.sleep()

        # shut down
        self.robot.setLDS("off")
        self.robot.setTestMode("off") 

    def cmdVelCb(self,req):
        x = req.linear.x * 1000
        th = req.angular.z * (BASE_WIDTH/2) 
        k = max(abs(x-th),abs(x+th))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            x = x*MAX_SPEED/k; th = th*MAX_SPEED/k
        self.cmd_vel = [ int(x-th) , int(x+th) ]
Ejemplo n.º 44
0
class OdometryClass:
    def __init__(self):
        self.ticks_sub = rospy.Subscriber('/encoders',encoders, self.getTicks)
        self.odom_pub = rospy.Publisher('/odom', Odometry, queue_size=1)
        self.odom_broadcaster = TransformBroadcaster()
        self.odom = Odometry()
        self.rate = rospy.Rate(10)
        self.lastLeftTicks = 0
        self.lastRightTicks = 0
        self.currentLeftTicks = 0
        self.currentRightTicks = 0
        self.last_time = rospy.Time.now()
        self.L = 0.601
        self.R = 0.07
        self.N = 360
        self.x = 0.0
        self.y = 0.0
        self.th = 0.0

    def getTicks(self, msg):
        self.currentLeftTicks = msg.encoderTicks[0]
        self.currentRightTicks = msg.encoderTicks[1]
    
    def updatePose(self):

        while not rospy.is_shutdown():
            current_time = rospy.Time.now()

            delta_l = self.currentLeftTicks - self.lastLeftTicks
            delta_r = self.currentRightTicks - self.lastRightTicks
            d_l = 2 * pi * self.R * delta_l / self.N
            d_r = 2 * pi * self.R * delta_r / self.N

            self.lastLeftTicks = self.currentLeftTicks
            self.lastRightTicks = self.currentRightTicks

            v = (d_r + d_l) / 2
            w = (d_r - d_l) / self.L

            # compute odometry in a typical way given the velocities of the robot
            dt = (current_time - self.last_time).to_sec()+0.0000000000000000000000000000000000000000001
            delta_x = v * cos(self.th)
            delta_y = v * sin(self.th)
            delta_th = w

            self.x += delta_x
            self.y += delta_y
            self.th += delta_th

            # since all odometry is 6DOF we'll need a quaternion created from yaw
            odom_quat = tf.transformations.quaternion_from_euler(0, 0, self.th)

            # first, we'll publish the transform over tf
            self.odom_broadcaster.sendTransform(
                (self.x, self.y, 0.),
                odom_quat,
                current_time,
                "base_link",
                "odom"
            )

            # next, we'll publish the odometry message over ROS
            odom = Odometry()
            odom.header.stamp = current_time
            odom.header.frame_id = "odom"

            # set the position
            odom.pose.pose = Pose(Point(self.x, self.y, 0.), Quaternion(*odom_quat))

            # set the velocity
            odom.child_frame_id = "base_link"
            odom.twist.twist = Twist(Vector3(v/dt, 0, 0), Vector3(0, 0, w/dt))

            # publish the message
            self.odom_pub.publish(odom)

            self.last_time = current_time
            self.rate.sleep()
Ejemplo n.º 45
0
class DiffTf:
    #############################################################################

    #############################################################################
    def __init__(self):
        #############################################################################
        rospy.init_node("base_odometry")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)

        #### parameters #######
        self.rate = rospy.get_param(
            '~rate', 10.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param(
            'ticks_meter',
            4900))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param(
            '~base_width', 0.5))  # The wheel base width in meters

        self.base_frame_id = rospy.get_param(
            '~base_frame_id',
            'base_link')  # the name of the base frame of the robot
        self.odom_frame_id = rospy.get_param(
            '~odom_frame_id',
            'odom')  # the name of the odometry reference frame

        self.encoder_min = rospy.get_param('encoder_min', -2147483647)
        self.encoder_max = rospy.get_param('encoder_max', 2147483647)
        self.encoder_low_wrap = rospy.get_param(
            'wheel_low_wrap',
            (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min)
        self.encoder_high_wrap = rospy.get_param(
            'wheel_high_wrap',
            (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min)

        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = rospy.Time.now() + self.t_delta

        # internal data
        self.enc_left = None  # wheel encoder readings
        self.enc_right = None
        self.left = 0  # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        self.dx = 0  # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()

        # subscriptions
        rospy.Subscriber("md49_encoders", md49_encoders, self.encodersCallback)
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=100)
        self.odomBroadcaster = TransformBroadcaster()

    #############################################################################
    def spin(self):
        #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()

    #############################################################################
    def update(self):
        #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()

            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right

            # distance traveled is the average of the two wheels
            d = (d_left + d_right) / 2
            # this approximation works (in radians) for small angles
            th = (d_right - d_left) / self.base_width
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed

            if (d != 0):
                # calculate distance traveled in x and y
                x = cos(th) * d
                y = -sin(th) * d
                # calculate the final position of the robot
                self.x = self.x + (cos(self.th) * x - sin(self.th) * y)
                self.y = self.y + (sin(self.th) * x + cos(self.th) * y)
            if (th != 0):
                self.th = self.th + th

            # publish the odom information
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2)
            quaternion.w = cos(self.th / 2)
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(), self.base_frame_id, self.odom_frame_id)

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)

    #############################################################################
    def encodersCallback(self, data):
        #############################################################################
        encL = data.encoder_l
        if (encL < self.encoder_low_wrap
                and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1

        if (encL > self.encoder_high_wrap
                and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1

        self.left = 1.0 * (encL + self.lmult *
                           (self.encoder_max - self.encoder_min))
        self.prev_lencoder = encL

        encR = data.encoder_r
        if (encR < self.encoder_low_wrap
                and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1

        if (encR > self.encoder_high_wrap
                and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1

        self.right = 1.0 * (encR + self.rmult *
                            (self.encoder_max - self.encoder_min))
        self.prev_rencoder = encR
Ejemplo n.º 46
0
def transformCallback(msg):
    br = TransformBroadcaster()
    br.sendTransform((marker_pose.translation.x, marker_pose.translation.y,
                      marker_pose.translation.z), (0, 0, 0, 1),
                     rospy.Time.now(), "fake_force_pose", "world")
Ejemplo n.º 47
0
class NeatoNode:
    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        self.port = rospy.get_param('~port', "/dev/ttyUSB0")
        rospy.loginfo("Using port: %s" % (self.port))

        self.robot = xv11(self.port)

        rospy.Subscriber("pi_cmd", String, self.pi_command)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('scan', LaserScan)
        self.odomPub = rospy.Publisher('odom', Odometry)
        self.bumpPub = rospy.Publisher('bump', Bump)
        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_to_send = None

        self.cmd_vel = [0, 0]

    def pi_command(self, msg):
        self.cmd_to_send = msg

    def spin(self):
        encoders = [0, 0]

        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id', 'base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link))
        scan.angle_min = 0
        scan.angle_max = 6.26
        scan.angle_increment = 0.017437326
        scan.range_min = 0.020
        scan.range_max = 5.0
        odom = Odometry(header=rospy.Header(frame_id="odom"),
                        child_frame_id='base_link')

        # main loop of driver
        r = rospy.Rate(5)
        rospy.sleep(4)
        self.robot.requestScan()
        scan.header.stamp = rospy.Time.now()
        last_motor_time = rospy.Time.now()
        total_dth = 0.0
        while not rospy.is_shutdown():
            if self.cmd_to_send != None:
                self.robot.send_command(self.cmd_to_send)
                self.cmd_to_send = None

            t_start = time.time()
            (scan.ranges, scan.intensities) = self.robot.getScanRanges()
            print 'Got scan ranges %f' % (time.time() - t_start)

            # get motor encoder values
            curr_motor_time = rospy.Time.now()
            t_start = time.time()
            try:
                left, right = self.robot.getMotors()
                # now update position information
                dt = (curr_motor_time - last_motor_time).to_sec()
                last_motor_time = curr_motor_time

                d_left = (left - encoders[0]) / 1000.0
                d_right = (right - encoders[1]) / 1000.0

                encoders = [left, right]
                dx = (d_left + d_right) / 2
                dth = (d_right - d_left) / (BASE_WIDTH / 1000.0)
                total_dth += dth

                x = cos(dth) * dx
                y = -sin(dth) * dx

                self.x += cos(self.th) * x - sin(self.th) * y
                self.y += sin(self.th) * x + cos(self.th) * y
                self.th += dth

                # prepare tf from base_link to odom
                quaternion = Quaternion()
                quaternion.z = sin(self.th / 2.0)
                quaternion.w = cos(self.th / 2.0)

                # prepare odometry
                odom.header.stamp = curr_motor_time
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = dx / dt
                odom.twist.twist.angular.z = dth / dt
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0),
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    curr_motor_time, "base_link", "odom")
                self.odomPub.publish(odom)
                print 'Got motors %f' % (time.time() - t_start)
            except:
                pass
            t_start = time.time()

            bump_sensors = self.robot.getDigitalSensors()

            # send updated movement commands
            self.robot.setMotors(
                self.cmd_vel[0], self.cmd_vel[1],
                max(abs(self.cmd_vel[0]), abs(self.cmd_vel[1])))
            print 'Set motors %f' % (time.time() - t_start)

            # publish everything
            self.scanPub.publish(scan)
            self.bumpPub.publish(
                Bump(leftFront=bump_sensors[0],
                     leftSide=bump_sensors[1],
                     rightFront=bump_sensors[2],
                     rightSide=bump_sensors[3]))
            self.robot.requestScan()
            scan.header.stamp = rospy.Time.now()

            # wait, then do it again
            r.sleep()

    def cmdVelCb(self, req):
        x = req.linear.x * 1000
        th = req.angular.z * (BASE_WIDTH / 2)
        k = max(abs(x - th), abs(x + th))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            x = x * MAX_SPEED / k
            th = th * MAX_SPEED / k
        self.cmd_vel = [int(x - th), int(x + th)]
        print self.cmd_vel, "SENDING THIS VEL"
Ejemplo n.º 48
0
class NeatoNode(object):
    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        host = rospy.get_param('~host')
        use_udp = rospy.get_param('~use_udp', True)
        rospy.loginfo("Connecting to host: %s" % (host))

        self.robot = xv11(host, use_udp)
        self.s = rospy.Service('reset_odom', Empty, self.handle_reset_odom)

        rospy.Subscriber('cmd_vel', Twist, self.cmdVelCb)
        rospy.Subscriber('raw_vel', Float32MultiArray, self.rawVelCb)

        self.scanPub = rospy.Publisher('scan', LaserScan, queue_size=10)
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.bumpPub = rospy.Publisher('bump', Int8MultiArray, queue_size=10)
        self.accelPub = rospy.Publisher('accel',
                                        Float32MultiArray,
                                        queue_size=10)
        self.encodersPub = rospy.Publisher('encoders',
                                           Float32MultiArray,
                                           queue_size=10)

        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_vel = None
        self.cmd_vel_lock = threading.Lock()

    def handle_reset_odom(self, req):
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0
        return EmptyResponse()

    def spin(self):
        old_ranges = None
        encoders = [0, 0]

        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id', 'base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link))
        scan.angle_min = -pi
        scan.angle_max = pi
        scan.angle_increment = pi / 180.0
        scan.range_min = 0.020
        scan.range_max = 5.0
        scan.time_increment = 1.0 / (5 * 360)
        scan.scan_time = 0.2
        odom = Odometry(header=rospy.Header(frame_id="odom"),
                        child_frame_id='base_link')

        # main loop of driver
        r = rospy.Rate(20)
        rospy.sleep(4)

        # do UDP hole punching to make sure the sensor data from the robot makes it through
        self.robot.do_udp_hole_punch()
        self.robot.send_keep_alive()
        last_keep_alive = time.time()

        self.robot.send_keep_alive()
        last_keep_alive = time.time()

        scan.header.stamp = rospy.Time.now()
        last_motor_time = rospy.Time.now()
        last_set_motor_time = rospy.Time.now()

        total_dth = 0.0
        while not rospy.is_shutdown():
            if time.time() - last_keep_alive > 30.0:
                self.robot.send_keep_alive()
                last_keep_alive = time.time()
            self.robot.requestScan()
            new_stamp = rospy.Time.now()
            delta_t = (new_stamp - scan.header.stamp).to_sec()
            scan.header.stamp = new_stamp
            (scan.ranges, scan.intensities) = self.robot.getScanRanges()
            # repeat last measurement to simulate -pi to pi (instead of -pi to pi - pi/180)
            # This is important in order to adhere to ROS conventions regarding laser scanners
            if len(scan.ranges):
                scan.ranges.append(scan.ranges[0])
                scan.intensities.append(scan.intensities[0])
                if old_ranges == scan.ranges:
                    scan.ranges, scan.intensities = [], []
                else:
                    old_ranges = copy(scan.ranges)

            if delta_t - 0.2 > 0.1:
                print "Iteration took longer than expected (should be 0.2) ", delta_t

            # get motor encoder values
            curr_motor_time = rospy.Time.now()
            try:
                motors = self.robot.getMotors()
                if motors:
                    # unpack the motor values since we got them.
                    left, right = motors
                    delta_t = (rospy.Time.now() - scan.header.stamp).to_sec()
                    # now update position information
                    # might consider moving curr_motor_time down
                    dt = (curr_motor_time - last_motor_time).to_sec()
                    last_motor_time = curr_motor_time

                    self.encodersPub.publish(
                        Float32MultiArray(data=[left / 1000.0, right /
                                                1000.0]))

                    d_left = (left - encoders[0]) / 1000.0
                    d_right = (right - encoders[1]) / 1000.0

                    encoders = [left, right]
                    dx = (d_left + d_right) / 2
                    dth = (d_right - d_left) / (BASE_WIDTH / 1000.0)
                    total_dth += dth

                    x_init = self.x
                    y_init = self.y
                    th_init = self.th

                    x = cos(dth) * dx
                    y = -sin(dth) * dx

                    self.x += cos(self.th) * x - sin(self.th) * y
                    self.y += sin(self.th) * x + cos(self.th) * y
                    self.th += dth

                    quaternion = Quaternion()
                    quaternion.z = sin(self.th / 2.0)
                    quaternion.w = cos(self.th / 2.0)

                    # prepare odometry
                    odom.header.stamp = curr_motor_time
                    odom.pose.pose.position.x = self.x
                    odom.pose.pose.position.y = self.y
                    odom.pose.pose.position.z = 0
                    odom.pose.pose.orientation = quaternion
                    odom.pose.covariance = [
                        10**-1, 0, 0, 0, 0, 0, 0, 10**-1, 0, 0, 0, 0, 0, 0,
                        10**-1, 0, 0, 0, 0, 0, 0, 10**5, 0, 0, 0, 0, 0, 0,
                        10**5, 0, 0, 0, 0, 0, 0, 10**5
                    ]
                    odom.twist.twist.linear.x = dx / dt
                    odom.twist.twist.angular.z = dth / dt
                    self.odomBroadcaster.sendTransform(
                        (self.x, self.y, 0), (quaternion.x, quaternion.y,
                                              quaternion.z, quaternion.w),
                        curr_motor_time, "base_link", "odom")
                    self.odomPub.publish(odom)
            except Exception as err:
                print "my error is " + str(err)
            with self.cmd_vel_lock:
                if self.cmd_vel:
                    self.robot.setMotors(
                        self.cmd_vel[0], self.cmd_vel[1],
                        max(abs(self.cmd_vel[0]), abs(self.cmd_vel[1])))
                    self.cmd_vel = None
                elif rospy.Time.now() - last_set_motor_time > rospy.Duration(
                        .2):
                    self.robot.resend_last_motor_command()
                    last_set_motor_time = rospy.Time.now()

            try:
                bump_sensors = self.robot.getDigitalSensors()
                if bump_sensors:
                    """ Indices of bump_sensors map as follows
                            0: front left
                            1: side left
                            2: front right
                            3: side right
                    """
                    self.bumpPub.publish(Int8MultiArray(data=bump_sensors))
            except:
                print "failed to get bump sensors!"

            try:
                accelerometer = self.robot.getAccel()
                if accelerometer:
                    # Indices 2, 3, 4 of accelerometer correspond to x, y, and z direction respectively
                    self.accelPub.publish(
                        Float32MultiArray(data=accelerometer[2:5]))
            except Exception as err:
                print "failed to get accelerometer!", err

            if len(scan.ranges):
                self.scanPub.publish(scan)
            # wait, then do it again
            r.sleep()

    def cmdVelCb(self, req):
        # Simple odometry model
        x = req.linear.x * 1000
        th = req.angular.z * (BASE_WIDTH / 2)
        k = max(abs(x - th), abs(x + th))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            x = x * MAX_SPEED / k
            th = th * MAX_SPEED / k
        with self.cmd_vel_lock:
            self.cmd_vel = [int(x - th), int(x + th)]
        #print self.cmd_vel, "SENDING THIS VEL"

    def rawVelCb(self, msg):
        if len(msg.data) == 2:
            self.cmd_vel = [int(1000.0 * x) for x in msg.data]
Ejemplo n.º 49
0
class BaseController:
    def __init__(self, arduino, base_frame):
        self.arduino = arduino
        self.base_frame = base_frame
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        self.timeout = rospy.get_param("~base_controller_timeout", 1.0)
        self.stopped = False
        self.useImu = rospy.get_param("~useImu", False)

        pid_params = dict()
        pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", "")
        pid_params['wheel_track'] = rospy.get_param("~wheel_track", "")
        pid_params['encoder_resolution'] = rospy.get_param(
            "~encoder_resolution", "")
        pid_params['gear_reduction'] = rospy.get_param("~gear_reduction", 1.0)
        pid_params['Kp'] = rospy.get_param("~Kp", 20)
        pid_params['Kd'] = rospy.get_param("~Kd", 12)
        pid_params['Ki'] = rospy.get_param("~Ki", 0)
        pid_params['Ko'] = rospy.get_param("~Ko", 50)

        self.accel_limit = rospy.get_param('~accel_limit', 0.1)
        self.motors_reversed = rospy.get_param("~motors_reversed", False)

        # Set up PID parameters and check for missing values
        self.setup_pid(pid_params)

        # How many encoder ticks are there per meter?
        self.ticks_per_meter = self.encoder_resolution * self.gear_reduction / (
            self.wheel_diameter * PI)

        # What is the maximum acceleration we will tolerate when changing wheel speeds?
        self.max_accel = self.accel_limit * self.ticks_per_meter / self.rate

        # Track how often we get a bad encoder count (if any)
        self.bad_encoder_count = 0

        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param(
            'wheel_low_wrap',
            (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min)
        self.encoder_high_wrap = rospy.get_param(
            'wheel_high_wrap',
            (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min)
        self.l_wheel_mult = 0
        self.r_wheel_mult = 0

        now = rospy.Time.now()
        self.then = now  # time for determining dx/dy
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = now + self.t_delta

        # Internal data
        self.enc_left = None  # encoder readings
        self.enc_right = None
        self.x = 0  # position in xy plane
        self.y = 0
        self.th = 0  # rotation in radians
        self.v_left = 0
        self.v_right = 0
        self.v_des_left = 0  # cmd_vel setpoint
        self.v_des_right = 0
        self.last_cmd_vel = now

        # Subscriptions
        #rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)
        rospy.Subscriber("smoother_cmd_vel", Twist, self.cmdVelCallback)

        # Clear any old odometry info
        self.arduino.reset_encoders()

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=5)
        self.odomBroadcaster = TransformBroadcaster()

        rospy.loginfo("Started base controller for a base of " +
                      str(self.wheel_track) + "m wide with " +
                      str(self.encoder_resolution) + " ticks per rev")
        rospy.loginfo("Publishing odometry data at: " + str(self.rate) +
                      " Hz using " + str(self.base_frame) + " as base frame")

        self.lEncoderPub = rospy.Publisher('Lencoder', Int16, queue_size=5)
        self.rEncoderPub = rospy.Publisher('Rencoder', Int16, queue_size=5)
        self.lVelPub = rospy.Publisher('Lvel', Int16, queue_size=5)
        self.rVelPub = rospy.Publisher('Rvel', Int16, queue_size=5)

    def setup_pid(self, pid_params):
        # Check to see if any PID parameters are missing
        missing_params = False
        for param in pid_params:
            if pid_params[param] == "":
                print("*** PID Parameter " + param + " is missing. ***")
                missing_params = True

        if missing_params:
            os._exit(1)

        self.wheel_diameter = pid_params['wheel_diameter']
        self.wheel_track = pid_params['wheel_track']
        self.encoder_resolution = pid_params['encoder_resolution']
        self.gear_reduction = pid_params['gear_reduction']

        self.Kp = pid_params['Kp']
        self.Kd = pid_params['Kd']
        self.Ki = pid_params['Ki']
        self.Ko = pid_params['Ko']

        self.arduino.update_pid(self.Kp, self.Kd, self.Ki, self.Ko)

    def poll(self):
        now = rospy.Time.now()
        if now > self.t_next:
            try:
                left_enc, right_enc = self.arduino.get_encoder_counts()
                #rospy.loginfo("left_enc: " + str(left_enc)+"right_enc: " + str(right_enc))
                self.lEncoderPub.publish(left_enc)
                self.rEncoderPub.publish(right_enc)
            except:
                self.bad_encoder_count += 1
                rospy.logerr("Encoder exception count: " +
                             str(self.bad_encoder_count))
                return

            dt = now - self.then
            self.then = now
            dt = dt.to_sec()

            # Calculate odometry
            if self.enc_left == None:
                dright = 0
                dleft = 0
            else:
                if (left_enc < self.encoder_low_wrap
                        and self.enc_left > self.encoder_high_wrap):
                    self.l_wheel_mult = self.l_wheel_mult + 1
                elif (left_enc > self.encoder_high_wrap
                      and self.enc_left < self.encoder_low_wrap):
                    self.l_wheel_mult = self.l_wheel_mult - 1
                else:
                    self.l_wheel_mult = 0
                if (right_enc < self.encoder_low_wrap
                        and self.enc_right > self.encoder_high_wrap):
                    self.r_wheel_mult = self.r_wheel_mult + 1
                elif (right_enc > self.encoder_high_wrap
                      and self.enc_right < self.encoder_low_wrap):
                    self.r_wheel_mult = self.r_wheel_mult - 1
                else:
                    self.r_wheel_mult = 0
                #dright = (right_enc - self.enc_right) / self.ticks_per_meter
                #dleft = (left_enc - self.enc_left) / self.ticks_per_meter
                dleft = 1.0 * (left_enc + self.l_wheel_mult *
                               (self.encoder_max - self.encoder_min) -
                               self.enc_left) / self.ticks_per_meter
                dright = 1.0 * (right_enc + self.r_wheel_mult *
                                (self.encoder_max - self.encoder_min) -
                                self.enc_right) / self.ticks_per_meter

            self.enc_right = right_enc
            self.enc_left = left_enc

            dxy_ave = (dright + dleft) / 2.0
            dth = (dright - dleft) / self.wheel_track
            vxy = dxy_ave / dt
            vth = dth / dt

            if (dxy_ave != 0):
                dx = cos(dth) * dxy_ave
                dy = -sin(dth) * dxy_ave
                self.x += (cos(self.th) * dx - sin(self.th) * dy)
                self.y += (sin(self.th) * dx + cos(self.th) * dy)

            if (dth != 0):
                self.th += dth

            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)

            # Create the odometry transform frame broadcaster.
            if (self.useImu == False):
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0),
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(), self.base_frame, "odom")

            odom = Odometry()
            odom.header.frame_id = "odom"
            odom.child_frame_id = self.base_frame
            odom.header.stamp = now
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = vxy
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = vth

            odom.pose.covariance = ODOM_POSE_COVARIANCE
            odom.twist.covariance = ODOM_TWIST_COVARIANCE
            # todo sensor_state.distance == 0
            #if self.v_des_left == 0 and self.v_des_right == 0:
            #    odom.pose.covariance = ODOM_POSE_COVARIANCE2
            #    odom.twist.covariance = ODOM_TWIST_COVARIANCE2
            #else:
            #    odom.pose.covariance = ODOM_POSE_COVARIANCE
            #    odom.twist.covariance = ODOM_TWIST_COVARIANCE

            self.odomPub.publish(odom)

            if now > (self.last_cmd_vel + rospy.Duration(self.timeout)):
                self.v_des_left = 0
                self.v_des_right = 0

            if self.v_left < self.v_des_left:
                self.v_left += self.max_accel
                if self.v_left > self.v_des_left:
                    self.v_left = self.v_des_left
            else:
                self.v_left -= self.max_accel
                if self.v_left < self.v_des_left:
                    self.v_left = self.v_des_left

            if self.v_right < self.v_des_right:
                self.v_right += self.max_accel
                if self.v_right > self.v_des_right:
                    self.v_right = self.v_des_right
            else:
                self.v_right -= self.max_accel
                if self.v_right < self.v_des_right:
                    self.v_right = self.v_des_right
            self.lVelPub.publish(self.v_left)
            self.rVelPub.publish(self.v_right)

            # Set motor speeds in encoder ticks per PID loop
            if not self.stopped:
                self.arduino.drive(self.v_left, self.v_right)

            self.t_next = now + self.t_delta

    def stop(self):
        self.stopped = True
        self.arduino.drive(0, 0)

    def cmdVelCallback(self, req):
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()

        x = req.linear.x  # m/s
        th = req.angular.z  # rad/s

        if x == 0:
            # Turn in place
            right = th * self.wheel_track * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track * self.gear_reduction / 2.0
            right = x + th * self.wheel_track * self.gear_reduction / 2.0

        self.v_des_left = int(left * self.ticks_per_meter)
        self.v_des_right = int(right * self.ticks_per_meter)
Ejemplo n.º 50
0
class ROSBaseControl:

    def __init__(self):
        rospy.init_node('base_control')
        self.finished = Event()
        self.controller = Controller('/dev/ttyS0')

        rospy.loginfo("Started base_control")
        print "Started base_control"

        # odom...
        self.rate = float(rospy.get_param("~base_controller_rate", 20))
        now = rospy.Time.now()

        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = now + self.t_delta
        self.then = now # time for determining dx/dy

        # internal data
        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0                 # rotation in radians
        self.vx = 0.0
        self.vy = 0.0
        self.vth = 0.0

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry)
        self.odomBroadcaster = TransformBroadcaster()

    def callback_cmd(self, msg):
        # TODO: from linear & radial velocities to linear vel on right/left wheel

        rospy.loginfo("Received a /cmd_vel message!")
        print "Received a /cmd_vel message!"

        # from m/s to controller velocity
        coef = 58823530
        # L = distance between wheels
        L = 0.495

        if msg.linear.x == 0 and msg.angular.z == 0:
            self.controller.stop_motor()
        else:
            rwheel_vel = (2*msg.linear.x - L*msg.angular.z)/2
            lwheel_vel = (2*msg.linear.x + L*msg.angular.z)/2
            print rwheel_vel, lwheel_vel
            self.controller.set_lwheel_velocity(abs(lwheel_vel*coef))
            self.controller.set_rwheel_velocity(abs(rwheel_vel*coef))
            self.controller.go_forward()

        self.vx = msg.linear.x
        #self.vth = msg.angular.z

    def listener(self):
        rospy.Subscriber('/cmd_vel', Twist, self.callback_cmd)

        rosRate = rospy.Rate(self.rate)

        while not rospy.is_shutdown() and not self.finished.isSet():
            now = rospy.Time.now()
            if now > self.t_next:
                dt = now - self.then
                self.then = now
                dt = dt.to_sec()

                delta_x = (self.vx * cos(self.th) - self.vy * sin(self.th)) * dt
                delta_y = (self.vx * sin(self.th) + self.vy * cos(self.th)) * dt
                delta_th = self.vth * dt

                self.x += delta_x
                self.y += delta_y
                self.th += delta_th

                quaternion = Quaternion()
                quaternion.x = 0.0
                quaternion.y = 0.0
                quaternion.z = sin(self.th / 2.0)
                quaternion.w = cos(self.th / 2.0)

                # Create the odometry transform frame broadcaster.
                self.odomBroadcaster.sendTransform(
                    (self.x, self.y, 0),
                    (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                    rospy.Time.now(),
                    "base_link",
                    "odom"
                    )

                odom = Odometry()
                odom.header.frame_id = "odom"
                odom.child_frame_id = "base_link"
                odom.header.stamp = now
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = self.vx
                odom.twist.twist.linear.y = 0
                odom.twist.twist.angular.z = self.vth

                self.odomPub.publish(odom)

                self.t_next = now + self.t_delta

            rosRate.sleep()
class DiffController(Controller):

    def __init__(self, node, name):
        Controller.__init__(self, node, name)
        self.last_cmd = rospy.Time.now()

        # Parameters: command timeout
        self.timeout = rospy.get_param("~controllers/"+name+"/timeout", 0.5)

        # Parameters: geometry
        self.ticks_meter = float(rospy.get_param("~controllers/"+name+"/ticks_meter"))
        self.base_width = float(rospy.get_param("~controllers/"+name+"/base_width"))

        self.base_frame_id = rospy.get_param("~controllers/"+name+"/base_frame_id", "base_link")
        self.odom_frame_id = rospy.get_param("~controllers/"+name+"/odom_frame_id", "odom")

        # Parameters: PID
        self.Kp = rospy.get_param("~controllers/"+name+"/Kp", 1.0)
        self.Kd = rospy.get_param("~controllers/"+name+"/Kd", 0.0)
        self.Ki = rospy.get_param("~controllers/"+name+"/Ki", 0.1)
        self.Kw = rospy.get_param("~controllers/"+name+"/Kw", 400.0)

        # Parameters: motor period
        self.period = rospy.get_param("~controllers/"+name+"/period", 10.0)

        # Parameters: acceleration
        self.accel_limit = rospy.get_param("~controllers/"+name+"/accel_limit", 0.1)

        # Parameters: twist covariance
        self.covariance_vx = rospy.get_param("~controllers/"+name+"/covariance_vx", 1e-3)
        self.covariance_vy = rospy.get_param("~controllers/"+name+"/covariance_vy", 1e-3)
        self.covariance_vz = rospy.get_param("~controllers/"+name+"/covariance_vz", 1e-6)
        self.covariance_wx = rospy.get_param("~controllers/"+name+"/covariance_wx", 1e-6)
        self.covariance_wy = rospy.get_param("~controllers/"+name+"/covariance_wy", 1e-6)
        self.covariance_wz = rospy.get_param("~controllers/"+name+"/covariance_wz", 1e-3)

        # Output for joint states publisher
        self.joint_names = ["base_l_wheel_joint", "base_r_wheel_joint"]
        self.joint_positions = [0.0, 0.0]
        self.joint_velocities = [0.0, 0.0]

        # Internal data
        self.v_left = 0                 # current setpoint velocity
        self.v_right = 0
        self.v_des_left = 0             # cmd_vel setpoint
        self.v_des_right = 0
        self.enc_left = None            # encoder readings
        self.enc_right = None
        self.x = 0                      # position in xy plane
        self.y = 0
        self.th = 0
        self.dx = 0                     # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()    # time for determining dx/dy

        # Publish odometry, optionally TF
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=5)
        self.odomBroadcaster = None
        if rospy.get_param("~controllers/"+name+"/publish_tf", True):
            self.odomBroadcaster = TransformBroadcaster()
		
        # Subscribe to command
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)

        rospy.loginfo("Started DiffController ("+name+").")
        rospy.loginfo("  Geometry: " + str(self.base_width) + "m wide, " + str(self.ticks_meter) + " ticks/m.")

    def update(self):
        now = rospy.Time.now()
        elapsed = now - self.then
        self.then = now
        elapsed = elapsed.to_sec()

        # Do odometry first
        if self.node.sim:
            # If simulated, forward simulate trajectory
            x = cos(self.th)*self.dx*elapsed
            y = -sin(self.th)*self.dx*elapsed
            self.x += cos(self.th)*self.dx*elapsed
            self.y += sin(self.th)*self.dx*elapsed
            self.th += self.dr*elapsed
        else:
            try:
                left = self.node.etherbotix.motor1_pos
                right = self.node.etherbotix.motor2_pos
            except AttributeError:
                # board is not yet updated
                return False

            # calculate position
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (left - self.enc_left)/self.ticks_meter
                d_right = (right - self.enc_right)/self.ticks_meter
            self.enc_left = left
            self.enc_right = right

            d = (d_left+d_right)/2
            th = (d_right-d_left)/self.base_width

            # calculate velocity
            l_vel = self.node.etherbotix.motor1_vel / self.ticks_meter
            r_vel = self.node.etherbotix.motor2_vel / self.ticks_meter
            self.dx = (l_vel+r_vel)/2 * (1000.0/self.period)
            self.dr = (r_vel-l_vel)/self.base_width * (1000.0/self.period)

            if (d != 0):
                x = cos(th)*d
                y = -sin(th)*d
                self.x = self.x + (cos(self.th)*x - sin(self.th)*y)
                self.y = self.y + (sin(self.th)*x + cos(self.th)*y)
            if (th != 0):
                self.th = self.th + th

            # Update joint_states publisher
            self.joint_positions = [self.enc_left/self.ticks_meter, self.enc_right/self.ticks_meter]
            self.joint_velocities = [l_vel * (1000.0/self.period), r_vel * (1000.0/self.period)]

        # Publish or perish
        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(self.th/2)
        quaternion.w = cos(self.th/2)
        if self.odomBroadcaster:
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )

        odom = Odometry()
        odom.header.stamp = now
        odom.header.frame_id = self.odom_frame_id
        odom.pose.pose.position.x = self.x
        odom.pose.pose.position.y = self.y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion
        odom.child_frame_id = self.base_frame_id
        odom.twist.twist.linear.x = self.dx
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = self.dr
        odom.twist.covariance[0] = self.covariance_vx
        odom.twist.covariance[7] = self.covariance_vy
        odom.twist.covariance[14] = self.covariance_vz
        odom.twist.covariance[21] = self.covariance_wx
        odom.twist.covariance[28] = self.covariance_wy
        odom.twist.covariance[35] = self.covariance_wz
        self.odomPub.publish(odom)

        # Now update commands
        if now > (self.last_cmd + rospy.Duration(self.timeout)):
            self.v_des_left = 0
            self.v_des_right = 0

        # Update motors if real hardware and PID is correct
        if not self.node.sim and self.updateParams():
            max_accel = int(self.accel_limit * self.ticks_meter * self.dt.to_sec())

            # Limit left side acceleration
            if self.v_left < self.v_des_left:
                self.v_left += max_accel
                if self.v_left > self.v_des_left:
                    self.v_left = self.v_des_left
            else:
                self.v_left -= max_accel
                if self.v_left < self.v_des_left:
                    self.v_left = self.v_des_left

            # Limit right side acceleration
            if self.v_right < self.v_des_right:
                self.v_right += max_accel
                if self.v_right > self.v_des_right:
                    self.v_right = self.v_des_right
            else:
                self.v_right -= max_accel
                if self.v_right < self.v_des_right:
                    self.v_right = self.v_des_right

            # Send commands
            self.updateControls(self.v_left, self.v_right)

    ## @brief On shutdown, need to stop base.
    def shutdown(self):
        self.updateControls(0,0)

    ## @brief ROS callback to set new velocity.
    ## @param req A geometry_msgs/Twist command.
    def cmdVelCb(self, req):
        # set motor speeds in ticks per period
        self.v_des_left = int( ((req.linear.x - (req.angular.z * self.base_width/2.0)) * self.ticks_meter) / (1000.0/self.period))
        self.v_des_right = int( ((req.linear.x + (req.angular.z * self.base_width/2.0)) * self.ticks_meter) / (1000.0/self.period))
        self.last_cmd = rospy.Time.now()

    ## @brief Get diagnostics message.
    def getDiagnostics(self):
        msg = DiagnosticStatus()
        msg.name = self.name
        msg.level = DiagnosticStatus.OK
        msg.message = "OK"
        if not self.node.sim:
            msg.values.append(KeyValue("Left", str(self.enc_left)))
            msg.values.append(KeyValue("Right", str(self.enc_right)))
        msg.values.append(KeyValue("dX", str(self.dx)))
        msg.values.append(KeyValue("dR", str(self.dr)))
        return msg

    ## @brief Make sure the parameters on robot match our params.
    ## @returns True if parameters match.
    def updateParams(self):
        # Need to check PID params
        if not almost_equal(self.node.etherbotix.motor1_kp, self.Kp) or \
           not almost_equal(self.node.etherbotix.motor1_kd, self.Kd) or \
           not almost_equal(self.node.etherbotix.motor1_ki, self.Ki) or \
           not almost_equal(self.node.etherbotix.motor1_windup, self.Kw) or \
           not almost_equal(self.node.etherbotix.motor2_kp, self.Kp) or \
           not almost_equal(self.node.etherbotix.motor2_kd, self.Kd) or \
           not almost_equal(self.node.etherbotix.motor2_ki, self.Ki) or \
           not almost_equal(self.node.etherbotix.motor2_windup, self.Kw):
            params = struct.pack("<ffff", self.Kp, self.Kd, self.Ki, self.Kw)
            params = params + params # both sides are the same
            params = [ord(x) for x in params]
            self.node.etherbotix.write(253, self.node.etherbotix.P_MOTOR1_KP, params, ret=False)
            return False
        # Need to check motor period
        if self.node.etherbotix.motor_period != self.period:
            self.node.etherbotix.write(253, self.node.etherbotix.P_MOTOR_PERIOD, [self.period,] , ret=False)
            return False
        # Params are up to date
        return True

    ## @brief Update controls
    def updateControls(self, left, right):
        params = struct.pack("<hh", left, right)
        params = [ord(x) for x in params]
        self.node.etherbotix.write(253, self.node.etherbotix.P_MOTOR1_VEL, params, ret=False)
Ejemplo n.º 52
0
class CreateDriver:
    def __init__(self):
        port = rospy.get_param('/brown/irobot_create_2_1/port', "/dev/ttyUSB0")
        self.create = Create(port)
        self.packetPub = rospy.Publisher('sensorPacket',
                                         SensorPacket,
                                         queue_size=10)
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        self.fields = [
            'wheeldropCaster', 'wheeldropLeft', 'wheeldropRight', 'bumpLeft',
            'bumpRight', 'wall', 'cliffLeft', 'cliffFronLeft',
            'cliffFrontRight', 'cliffRight', 'virtualWall', 'infraredByte',
            'advance', 'play', 'distance', 'angle', 'chargingState', 'voltage',
            'current', 'batteryTemperature', 'batteryCharge',
            'batteryCapacity', 'wallSignal', 'cliffLeftSignal',
            'cliffFrontLeftSignal', 'cliffFrontRightSignal',
            'cliffRightSignal', 'homeBase', 'internalCharger', 'songNumber',
            'songPlaying'
        ]
        self.then = datetime.now()
        self.x = 0
        self.y = 0
        self.th = 0
        self.create.update = self.sense

    def start(self):
        self.create.start()
        self.then = datetime.now()

    def stop(self):
        self.create.stop()

    def sense(self):
        now = datetime.now()
        elapsed = now - self.then
        self.then = now
        elapsed = float(elapsed.seconds) + elapsed.microseconds / 1000000.
        d = self.create.d_distance / 1000.
        th = self.create.d_angle * pi / 180
        dx = d / elapsed
        dth = th / elapsed

        if (d != 0):
            x = cos(th) * d
            y = -sin(th) * d
            self.x = self.x + (cos(self.th) * x - sin(self.th) * y)
            self.y = self.y + (sin(self.th) * x + cos(self.th) * y)

        if (th != 0):
            self.th = self.th + th

        quaternion = Quaternion()
        quaternion.x = 0.0
        quaternion.y = 0.0
        quaternion.z = sin(self.th / 2)
        quaternion.w = cos(self.th / 2)

        self.odomBroadcaster.sendTransform(
            (self.x, self.y, 0),
            (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
            rospy.Time.now(), "base_link", "odom")

        odom = Odometry()
        odom.header.stamp = rospy.Time.now()
        odom.header.frame_id = "odom"
        odom.pose.pose.position.x = self.x
        odom.pose.pose.position.y = self.y
        odom.pose.pose.position.z = 0
        odom.pose.pose.orientation = quaternion

        odom.child_frame_id = "base_link"
        odom.twist.twist.linear.x = dx
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = dth

        self.odomPub.publish(odom)

        packet = SensorPacket()
        for field in self.fields:
            packet.__setattr__(field, self.create.__getattr__(field))
        self.packetPub.publish(packet)

    def brake(self, req):
        if (req.brake):
            self.create.brake()
        return BrakeResponse(True)

    def circle(self, req):
        if (req.clear):
            self.create.clear()
        self.create.forwardTurn(req.speed, req.radius)
        return CircleResponse(True)

    def demo(self, req):
        self.create.demo(req.demo)
        return DemoResponse(True)

    def leds(self, req):
        self.create.leds(req.advance, req.play, req.color, req.intensity)
        return LedsResponse(True)

    def tank(self, req):
        if (req.clear):
            self.create.clear()
        self.create.tank(req.left, req.right)
        return TankResponse(True)

    def turn(self, req):
        if (req.clear):
            self.create.clear()
        self.create.turn(req.turn)
        return TurnResponse(True)

    def twist(self, req):
        x = req.linear.x * 1000.
        th = req.angular.z
        if (x == 0):
            th = th * 180 / pi
            speed = (8 * pi * th) / 9
            self.create.left(int(speed))
        elif (th == 0):
            x = int(x)
            self.create.tank(x, x)
        else:
            self.create.forwardTurn(int(x), int(x / th))
Ejemplo n.º 53
0
class NeatoNode:

    def __init__(self):
        """ Start up connection to the Neato Robot. """
        rospy.init_node('neato')

        self.tf_prefix = rospy.get_param('~tf_prefix', "")
        self.port = rospy.get_param('~port', "/dev/ttyUSB0")
        rospy.loginfo("Using port: %s"%(self.port))

        self.robot = xv11(self.port)

        rospy.Subscriber("pi_cmd",String,self.pi_command)

        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.scanPub = rospy.Publisher('scan', LaserScan)
        self.odomPub = rospy.Publisher('odom',Odometry)
        self.odomBroadcaster = TransformBroadcaster()

        self.cmd_to_send = None

        self.cmd_vel = [0,0]

    def pi_command(self,msg):
        self.cmd_to_send = msg

    def spin(self):        
        encoders = [0,0]

        self.x = 0                  # position in xy plane
        self.y = 0
        self.th = 0

        # things that don't ever change
        scan_link = rospy.get_param('~frame_id','base_laser_link')
        scan = LaserScan(header=rospy.Header(frame_id=scan_link)) 
        scan.angle_min = 0
        scan.angle_max = 6.26
        scan.angle_increment = 0.017437326
        scan.range_min = 0.020
        scan.range_max = 5.0
        odom = Odometry(header=rospy.Header(frame_id="odom"), child_frame_id='base_link')
    
        # main loop of driver
        r = rospy.Rate(5)
        rospy.sleep(4)
        self.robot.requestScan()
        scan.header.stamp = rospy.Time.now()
        last_motor_time = rospy.Time.now()
        total_dth = 0.0
        while not rospy.is_shutdown():
            if self.cmd_to_send != None:
                self.robot.send_command(self.cmd_to_send)
                self.cmd_to_send = None

            t_start = time.time()
            (scan.ranges, scan.intensities) = self.robot.getScanRanges()
            print 'Got scan ranges %f' % (time.time() - t_start)

            # get motor encoder values
            curr_motor_time = rospy.Time.now()
            t_start = time.time()
            try:
                left, right = self.robot.getMotors()
                # now update position information
                dt = (curr_motor_time - last_motor_time).to_sec()
                last_motor_time = curr_motor_time

                d_left = (left - encoders[0])/1000.0
                d_right = (right - encoders[1])/1000.0

                encoders = [left, right]
                dx = (d_left+d_right)/2
                dth = (d_right-d_left)/(BASE_WIDTH/1000.0)
                total_dth += dth

                x = cos(dth)*dx
                y = -sin(dth)*dx

                self.x += cos(self.th)*x - sin(self.th)*y
                self.y += sin(self.th)*x + cos(self.th)*y
                self.th += dth

                # prepare tf from base_link to odom
                quaternion = Quaternion()
                quaternion.z = sin(self.th/2.0)
                quaternion.w = cos(self.th/2.0)

                # prepare odometry
                odom.header.stamp = curr_motor_time
                odom.pose.pose.position.x = self.x
                odom.pose.pose.position.y = self.y
                odom.pose.pose.position.z = 0
                odom.pose.pose.orientation = quaternion
                odom.twist.twist.linear.x = dx/dt
                odom.twist.twist.angular.z = dth/dt
                self.odomBroadcaster.sendTransform( (self.x, self.y, 0), (quaternion.x, quaternion.y, quaternion.z, quaternion.w), curr_motor_time, self.tf_prefix + "/base_link", self.tf_prefix + "/odom" )
                self.odomPub.publish(odom)
                print 'Got motors %f' % (time.time() - t_start)
            except:
                pass
            t_start = time.time()            
            # send updated movement commands
            self.robot.setMotors(self.cmd_vel[0], self.cmd_vel[1], max(abs(self.cmd_vel[0]),abs(self.cmd_vel[1])))
            print 'Set motors %f' % (time.time() - t_start)


            # publish everything
            self.scanPub.publish(scan)
            self.robot.requestScan()
            scan.header.stamp = rospy.Time.now()

            # wait, then do it again
            r.sleep()

    def cmdVelCb(self,req):
        x = req.linear.x * 1000
        th = req.angular.z * (BASE_WIDTH/2) 
        k = max(abs(x-th),abs(x+th))
        # sending commands higher than max speed will fail
        if k > MAX_SPEED:
            x = x*MAX_SPEED/k; th = th*MAX_SPEED/k
        self.cmd_vel = [ int(x-th) , int(x+th) ]
        print self.cmd_vel, "SENDING THIS VEL"
Ejemplo n.º 54
0
class DiffController(Controller):
    """ Controller to handle movement & odometry feedback for a differential
            drive mobile base. """
    def __init__(self, device, name):
        Controller.__init__(self, device, name)
        self.pause = True
        self.last_cmd = rospy.Time.now()

        # parameters: rates and geometry
        self.rate = rospy.get_param('~controllers/'+name+'/rate',10.0)
        self.timeout = rospy.get_param('~controllers/'+name+'/timeout',1.0)
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = rospy.Time.now() + self.t_delta
        self.ticks_meter = float(rospy.get_param('~controllers/'+name+'/ticks_meter'))
        self.base_width = float(rospy.get_param('~controllers/'+name+'/base_width'))

        self.base_frame_id = rospy.get_param('~controllers/'+name+'/base_frame_id', 'base_link')
        self.odom_frame_id = rospy.get_param('~controllers/'+name+'/odom_frame_id', 'odom')

        # parameters: PID
        self.Kp = rospy.get_param('~controllers/'+name+'/Kp', 5)
        self.Kd = rospy.get_param('~controllers/'+name+'/Kd', 1)
        self.Ki = rospy.get_param('~controllers/'+name+'/Ki', 0)
        self.Ko = rospy.get_param('~controllers/'+name+'/Ko', 50)

        # parameters: acceleration
        self.accel_limit = rospy.get_param('~controllers/'+name+'/accel_limit', 0.1)
        self.max_accel = int(self.accel_limit*self.ticks_meter/self.rate)

        # output for joint states publisher
        self.joint_names = ["left_wheel_joint","right_wheel_joint"]
        self.joint_positions = [0,0]
        self.joint_velocities = [0,0]

        # internal data
        self.v_left = 0                 # current setpoint velocity
        self.v_right = 0
        self.v_des_left = 0             # cmd_vel setpoint
        self.v_des_right = 0
        self.enc_left = None            # encoder readings
        self.enc_right = None
        self.x = 0                      # position in xy plane
        self.y = 0
        self.th = 0
        self.dx = 0                     # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()    # time for determining dx/dy

        # subscriptions
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCb)
        self.odomPub = rospy.Publisher("odom", Odometry, queue_size=5)
        self.odomBroadcaster = TransformBroadcaster()

        rospy.loginfo("Started DiffController ("+name+"). Geometry: " + str(self.base_width) + "m wide, " + str(self.ticks_meter) + " ticks/m.")

    def startup(self):
        if not self.fake:
            self.setup(self.Kp,self.Kd,self.Ki,self.Ko)

    def update(self):
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()

            if self.fake:
                x = cos(self.th)*self.dx*elapsed
                y = -sin(self.th)*self.dx*elapsed
                self.x += cos(self.th)*self.dx*elapsed
                self.y += sin(self.th)*self.dx*elapsed
                self.th += self.dr*elapsed
            else:
                # read encoders
                try:
                    left, right = self.status()
                except Exception as e:
                    rospy.logerr("Could not update encoders: " + str(e))
                    return
                rospy.logdebug("Encoders: " + str(left) +","+ str(right))

                # calculate odometry
                if self.enc_left == None:
                    d_left = 0
                    d_right = 0
                else:
                    d_left = (left - self.enc_left)/self.ticks_meter
                    d_right = (right - self.enc_right)/self.ticks_meter
                self.enc_left = left
                self.enc_right = right

                d = (d_left+d_right)/2
                th = (d_right-d_left)/self.base_width
                self.dx = d / elapsed
                self.dr = th / elapsed

                if (d != 0):
                    x = cos(th)*d
                    y = -sin(th)*d
                    self.x = self.x + (cos(self.th)*x - sin(self.th)*y)
                    self.y = self.y + (sin(self.th)*x + cos(self.th)*y)
                if (th != 0):
                    self.th = self.th + th

            # publish or perish
            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th/2)
            quaternion.w = cos(self.th/2)
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )

            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)

            if now > (self.last_cmd + rospy.Duration(self.timeout)):
                self.v_des_left = 0
                self.v_des_right = 0

            # update motors
            if not self.fake:
                if self.v_left < self.v_des_left:
                    self.v_left += self.max_accel
                    if self.v_left > self.v_des_left:
                        self.v_left = self.v_des_left
                else:
                    self.v_left -= self.max_accel
                    if self.v_left < self.v_des_left:
                        self.v_left = self.v_des_left

                if self.v_right < self.v_des_right:
                    self.v_right += self.max_accel
                    if self.v_right > self.v_des_right:
                        self.v_right = self.v_des_right
                else:
                    self.v_right -= self.max_accel
                    if self.v_right < self.v_des_right:
                        self.v_right = self.v_des_right
                self.write(self.v_left, self.v_right)

            self.t_next = now + self.t_delta

    def shutdown(self):
        if not self.fake:
            self.write(0,0)

    def cmdVelCb(self,req):
        """ Handle movement requests. """
        self.last_cmd = rospy.Time.now()
        if self.fake:
            self.dx = req.linear.x        # m/s
            self.dr = req.angular.z       # rad/s
        else:
            # set motor speeds in ticks per 1/30s
            self.v_des_left = int( ((req.linear.x - (req.angular.z * self.base_width/2.0)) * self.ticks_meter) / 30.0)
            self.v_des_right = int( ((req.linear.x + (req.angular.z * self.base_width/2.0)) * self.ticks_meter) / 30.0)

    def getDiagnostics(self):
        """ Get a diagnostics status. """
        msg = DiagnosticStatus()
        msg.name = self.name
        msg.level = DiagnosticStatus.OK
        msg.message = "OK"
        if not self.fake:
            msg.values.append(KeyValue("Left", str(self.enc_left)))
            msg.values.append(KeyValue("Right", str(self.enc_right)))
        msg.values.append(KeyValue("dX", str(self.dx)))
        msg.values.append(KeyValue("dR", str(self.dr)))
        return msg

    ###
    ### Controller Specification:
    ###
    ###  setup: Kp, Kd, Ki, Ko (all unsigned char)
    ###
    ###  write: left_speed, right_speed (2-byte signed, ticks per frame)
    ###
    ###  status: left_enc, right_enc (4-byte signed)
    ###

    def setup(self, kp, kd, ki, ko):
        success = self.device.execute(253, AX_CONTROL_SETUP, [10, kp, kd, ki, ko])

    def write(self, left, right):
        """ Send a closed-loop speed. Base PID loop runs at 30Hz, these values
                are therefore in ticks per 1/30 second. """
        left = left&0xffff
        right = right&0xffff
        success = self.device.execute(253, AX_CONTROL_WRITE, [10, left%256, left>>8, right%256, right>>8])

    def status(self):
        """ read 32-bit (signed) encoder values. """
        values = self.device.execute(253, AX_CONTROL_STAT, [10])
        left_values = "".join([chr(k) for k in values[0:4] ])
        right_values = "".join([chr(k) for k in values[4:] ])
        try:
            left = unpack('=l',left_values)[0]
            right = unpack('=l',right_values)[0]
            return [left, right]
        except:
            return None
Ejemplo n.º 55
0
class BaseController:
    def __init__(self, arduino):
        self.arduino = arduino
        self.rate = float(rospy.get_param("~base_controller_rate", 10))
        self.timeout = rospy.get_param('~base_controller_timeout', 1.0)
        self.stopped = False
                 
        pid_params = dict()
        pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", "") 
        pid_params['wheel_track'] = rospy.get_param("~wheel_track", "")
        pid_params['encoder_resolution'] = rospy.get_param("~encoder_resolution", "") 
        pid_params['gear_reduction'] = rospy.get_param("~gear_reduction", 1.0)
        pid_params['Kp'] = rospy.get_param("~Kp", 20)
        pid_params['Kd'] = rospy.get_param("~Kd", 12)
        pid_params['Ki'] = rospy.get_param("~Ki", 0)
        pid_params['Ko'] = rospy.get_param("~Ko", 50)
        
        self.accel_limit = rospy.get_param('~accel_limit', 0.1)
        self.motors_reversed = rospy.get_param("~motors_reversed", False)
        
        # Used to Determin which cmd_vel to listen to
        self.cmdvel2 = False
        # Set up PID parameters and check for missing values
        self.setup_pid(pid_params)
            
        # How many encoder ticks are there per meter?
        self.ticks_per_meter = self.encoder_resolution * self.gear_reduction  / (self.wheel_diameter * pi)
        
        # What is the maximum acceleration we will tolerate when changing wheel speeds?
        self.max_accel = self.accel_limit * self.ticks_per_meter / self.rate
                
        # Track how often we get a bad encoder count (if any)
        self.bad_encoder_count = 0
                        
        now = rospy.Time.now()    
        self.then = now # time for determining dx/dy
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = now + self.t_delta

        # internal data        
        self.enc_left = None            # encoder readings
        self.enc_right = None
        self.x = 0                      # position in xy plane
        self.y = 0
        self.th = 0                     # rotation in radians
        self.v_left = 0
        self.v_right = 0
        self.v_des_left = 0             # cmd_vel setpoint
        self.v_des_right = 0
        self.last_cmd_vel = now

        # subscriptions
        rospy.Subscriber("cmd_vel", Twist, self.cmdVelCallback)
        rospy.Subscriber("cmd_vel2", Twist, self.cmdVel2Callback)
        
        # Clear any old odometry info
        self.arduino.reset_encoders()
        
        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=10)
        self.odomBroadcaster = TransformBroadcaster()
        
        rospy.loginfo("Started base controller for a base of " + str(self.wheel_track) + "m wide with " + str(self.encoder_resolution) + " ticks per rev")
        rospy.loginfo("Publishing odometry data at: " + str(self.rate) + " Hz")
        
    def setup_pid(self, pid_params):
        # Check to see if any PID parameters are missing
        missing_params = False
        for param in pid_params:
            if pid_params[param] == "":
                print("*** PID Parameter " + param + " is missing. ***")
                missing_params = True
        
        if missing_params:
            os._exit(1)
                
        self.wheel_diameter = pid_params['wheel_diameter']
        self.wheel_track = pid_params['wheel_track']
        self.encoder_resolution = pid_params['encoder_resolution']
        self.gear_reduction = pid_params['gear_reduction']
        
        self.Kp = pid_params['Kp']
        self.Kd = pid_params['Kd']
        self.Ki = pid_params['Ki']
        self.Ko = pid_params['Ko']
        
        self.arduino.update_pid(self.Kp, self.Kd, self.Ki, self.Ko)

    def poll(self):
        now = rospy.Time.now()
        if now > self.t_next:
            # Read the encoders
            try:
                left_enc, right_enc = self.arduino.get_encoder_counts()
            except:
                self.bad_encoder_count += 1
                rospy.logerr("Encoder exception count: " + str(self.bad_encoder_count))
                return
                            
            dt = now - self.then
            self.then = now
            dt = dt.to_sec()
            
            # calculate odometry
            if self.enc_left == None:
                dright = 0
                dleft = 0
            else:
                dright = (right_enc - self.enc_right) / self.ticks_per_meter
                dleft = (left_enc - self.enc_left) / self.ticks_per_meter

            self.enc_right = right_enc
            self.enc_left = left_enc
            
            dxy_ave = (dright + dleft) / 2.0
            dth = (dright - dleft) / self.wheel_track
            vxy = dxy_ave / dt
            vth = dth / dt
                
            if (dxy_ave != 0):
                dx = cos(dth) * dxy_ave
                dy = -sin(dth) * dxy_ave
                self.x += (cos(self.th) * dx - sin(self.th) * dy)
                self.y += (sin(self.th) * dx + cos(self.th) * dy)
    
            if (dth != 0):
                self.th += dth 
    
            quaternion = Quaternion()
            quaternion.x = 0.0 
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)
    
            # Create the odometry transform frame broadcaster.
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0), 
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                "base_link",
                "odom"
                )
    
            odom = Odometry()
            odom.header.frame_id = "odom"
            odom.child_frame_id = "base_link"
            odom.header.stamp = now
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            odom.twist.twist.linear.x = vxy
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = vth

            self.odomPub.publish(odom)
            
            if now > (self.last_cmd_vel + rospy.Duration(self.timeout)):
                self.v_des_left = 0
                self.v_des_right = 0
                
            if self.v_left < self.v_des_left:
                self.v_left += self.max_accel
                if self.v_left > self.v_des_left:
                    self.v_left = self.v_des_left
            else:
                self.v_left -= self.max_accel
                if self.v_left < self.v_des_left:
                    self.v_left = self.v_des_left
            
            if self.v_right < self.v_des_right:
                self.v_right += self.max_accel
                if self.v_right > self.v_des_right:
                    self.v_right = self.v_des_right
            else:
                self.v_right -= self.max_accel
                if self.v_right < self.v_des_right:
                    self.v_right = self.v_des_right
            
            # Set motor speeds in encoder ticks per PID loop
            if not self.stopped:
                self.arduino.drive(self.v_left, self.v_right)
                
            self.t_next = now + self.t_delta
            
    def stop(self):
        self.stopped = True
        self.arduino.drive(0, 0)
            
    def cmdVelCallback(self, req):
        #check if we are using cmd_vel2 at the moment
        if self.cmdvel2:
            return
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()
        
        x = req.linear.x         # m/s
        th = req.angular.z       # rad/s

        if x == 0:
            # Turn in place
            right = th * self.wheel_track  * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track  * self.gear_reduction / 2.0
            right = x + th * self.wheel_track  * self.gear_reduction / 2.0
            
        self.v_des_left = int(left * self.ticks_per_meter / self.arduino.PID_RATE)
        self.v_des_right = int(right * self.ticks_per_meter / self.arduino.PID_RATE)
    def cmdVel2Callback(self, req):
        # Got a request, shut off cmd_vel
        self.cmdvel2 = True
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()
        
        x = req.linear.x         # m/s
        th = req.angular.z       # rad/s
        
        if x == 0:
            # if we are not turning in place, then go back to cmd_vel
            if th == 0:
                self.cmdvel2 = False
            # Turn in place
            right = th * self.wheel_track  * self.gear_reduction / 2.0
            left = -right
        elif th == 0:
            # Pure forward/backward motion
            left = right = x
        else:
            # Rotation about a point in space
            left = x - th * self.wheel_track  * self.gear_reduction / 2.0
            right = x + th * self.wheel_track  * self.gear_reduction / 2.0
            
        self.v_des_left = int(left * self.ticks_per_meter / self.arduino.PID_RATE)
        self.v_des_right = int(right * self.ticks_per_meter / self.arduino.PID_RATE)
Ejemplo n.º 56
0
class BaseController:
    def __init__(self, arduino, base_frame, name="base_controllers"):
        self.arduino = arduino
        self.name = name
        self.base_frame = base_frame
        self.rate = float(rospy.get_param("~base_controller_rate", 20))
        self.timeout = rospy.get_param("~base_controller_timeout", 0.3)
        self.accel_limit = rospy.get_param('~accel_limit', 0.05)
        self.debugPID = rospy.get_param('~debugPID', False)
        self.motors_reversed = rospy.get_param("~motors_reversed", False)
        self.linear_scale_correction = rospy.get_param("~linear_scale_correction", 1.0)
        self.angular_scale_correction = rospy.get_param("~angular_scale_correction", 1.0)
        self.stopped = False

        pid_params = dict()
        pid_params['wheel_diameter'] = rospy.get_param("~wheel_diameter", "")
        pid_params['wheel_track'] = rospy.get_param("~wheel_track", "")
        pid_params['encoder_resolution'] = rospy.get_param("~encoder_resolution", "")
        pid_params['gear_reduction'] = rospy.get_param("~gear_reduction", 1.0)
        
        pid_params['AWheel_Kp'] = rospy.get_param("~AWheel_Kp", 11)
        pid_params['AWheel_Kd'] = rospy.get_param("~AWheel_Kd", 15)
        pid_params['AWheel_Ki'] = rospy.get_param("~AWheel_Ki", 0)
        pid_params['AWheel_Ko'] = rospy.get_param("~AWheel_Ko", 50)

        pid_params['BWheel_Kp'] = rospy.get_param("~BWheel_Kp", 11)
        pid_params['BWheel_Kd'] = rospy.get_param("~BWheel_Kd", 15)
        pid_params['BWheel_Ki'] = rospy.get_param("~BWheel_Ki", 0)
        pid_params['BWheel_Ko'] = rospy.get_param("~BWheel_Ko", 50)

        pid_params['CWheel_Kp'] = rospy.get_param("~CWheel_Kp", 11)
        pid_params['CWheel_Kd'] = rospy.get_param("~CWheel_Kd", 16)
        pid_params['CWheel_Ki'] = rospy.get_param("~CWheel_Ki", 0)
        pid_params['CWheel_Ko'] = rospy.get_param("~CWheel_Ko", 50)
        
        pid_params['DWheel_Kp'] = rospy.get_param("~DWheel_Kp", 11)
        pid_params['DWheel_Kd'] = rospy.get_param("~DWheel_Kd", 16)
        pid_params['DWheel_Ki'] = rospy.get_param("~DWheel_Ki", 0)
        pid_params['DWheel_Ko'] = rospy.get_param("~DWheel_Ko", 50)
        

        # Set up PID parameters and check for missing values
        self.setup_pid(pid_params)

        # How many encoder ticks are there per meter?
        self.ticks_per_meter = self.encoder_resolution * self.gear_reduction * 2 / (self.wheel_diameter * pi) 
        self.ticks_per_meter = self.ticks_per_meter * self.linear_scale_correction
        # What is the maximum acceleration we will tolerate when changing wheel speeds?
        self.max_accel = self.accel_limit * self.ticks_per_meter / self.rate

        # Track how often we get a bad encoder count (if any)
        self.bad_encoder_count = 0

        now = rospy.Time.now()
        self.then = now # time for determining dx/dy
        self.t_delta = rospy.Duration(1.0 / self.rate)
        self.t_next = now + self.t_delta

        # Internal data
        self.enc_A = None            # encoder readings
        self.enc_B = None
        self.enc_C = None
        self.enc_D = None

        self.x  = 0                  # position in xy plane
        self.y  = 0
        self.th = 0                  # rotation in radians

        self.v_A = 0
        self.v_B = 0
        self.v_C = 0
        self.v_D = 0

        self.v_des_AWheel = 0        # cmd_vel setpoint
        self.v_des_BWheel = 0
        self.v_des_CWheel = 0
        self.v_des_DWheel = 0

        self.last_cmd_vel = now

        # Subscriptions
        rospy.Subscriber("/smooth_cmd_vel", Twist, self.cmdVelCallback)

        # Clear any old odometry info
        self.arduino.reset_encoders()

        # Set up the odometry broadcaster
        self.odomPub = rospy.Publisher('odom', Odometry, queue_size=5)
        self.odomBroadcaster = TransformBroadcaster()

        # rqt_plot debug pid
        if self.debugPID:
            self.AEncoderPub = rospy.Publisher('Aencoder', Int32, queue_size=10)
            self.BEncoderPub = rospy.Publisher('Bencoder', Int32, queue_size=10)
            self.CEncoderPub = rospy.Publisher('Cencoder', Int32, queue_size=10)
            self.DEncoderPub = rospy.Publisher('Dencoder', Int32, queue_size=10)
            
            self.APidoutPub  = rospy.Publisher('Apidout',  Int32, queue_size=10)
            self.BPidoutPub  = rospy.Publisher('Bpidout',  Int32, queue_size=10)
            self.CPidoutPub  = rospy.Publisher('Cpidout',  Int32, queue_size=10)
            self.DPidoutPub  = rospy.Publisher('Dpidout',  Int32, queue_size=10)
            
            self.AVelPub     = rospy.Publisher('Avel',     Int32, queue_size=10)
            self.BVelPub     = rospy.Publisher('Bvel',     Int32, queue_size=10)
            self.CVelPub     = rospy.Publisher('Cvel',     Int32, queue_size=10)
            self.DVelPub     = rospy.Publisher('Dvel',     Int32, queue_size=10)

        rospy.loginfo("Started base controller for a base of " + str(self.wheel_track) + "m wide with " + str(self.encoder_resolution) + " ticks per rev")
        rospy.loginfo("Publishing odometry data at: " + str(self.rate) + " Hz using " + str(self.base_frame) + " as base frame")

    def setup_pid(self, pid_params):
        # Check to see if any PID parameters are missing
        missing_params = False
        for param in pid_params:
            if pid_params[param] == "":
                print("*** PID Parameter " + param + " is missing. ***")
                missing_params = True

        if missing_params:
            os._exit(1)

        self.wheel_diameter = pid_params['wheel_diameter']
        self.wheel_track = pid_params['wheel_track']
        self.wheel_track = self.wheel_track * self.angular_scale_correction
        self.encoder_resolution = pid_params['encoder_resolution']
        self.gear_reduction = pid_params['gear_reduction']

        self.AWheel_Kp = pid_params['AWheel_Kp']
        self.AWheel_Kd = pid_params['AWheel_Kd']
        self.AWheel_Ki = pid_params['AWheel_Ki']
        self.AWheel_Ko = pid_params['AWheel_Ko']

        self.BWheel_Kp = pid_params['BWheel_Kp']
        self.BWheel_Kd = pid_params['BWheel_Kd']
        self.BWheel_Ki = pid_params['BWheel_Ki']
        self.BWheel_Ko = pid_params['BWheel_Ko']

        self.CWheel_Kp = pid_params['CWheel_Kp']
        self.CWheel_Kd = pid_params['CWheel_Kd']
        self.CWheel_Ki = pid_params['CWheel_Ki']
        self.CWheel_Ko = pid_params['CWheel_Ko']
        
        self.DWheel_Kp = pid_params['DWheel_Kp']
        self.DWheel_Kd = pid_params['DWheel_Kd']
        self.DWheel_Ki = pid_params['DWheel_Ki']
        self.DWheel_Ko = pid_params['DWheel_Ko']

        self.arduino.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,
                                self.CWheel_Kp, self.CWheel_Kd, self.CWheel_Ki, self.CWheel_Ko,self.DWheel_Kp, self.DWheel_Kd, self.DWheel_Ki, self.DWheel_Ko)

    def poll(self):
        if self.debugPID:
            try:
                A_pidin, B_pidin, C_pidin, D_pidin = self.arduino.get_pidin()
                self.AEncoderPub.publish(A_pidin)
                self.BEncoderPub.publish(B_pidin)
                self.CEncoderPub.publish(C_pidin)
                self.DEncoderPub.publish(D_pidin)
            except:
                rospy.logerr("getpidin exception count:")
                return

            try:
                A_pidout, B_pidout, C_pidout, D_pidout = self.arduino.get_pidout()
                self.APidoutPub.publish(A_pidout)
                self.BPidoutPub.publish(B_pidout)
                self.CPidoutPub.publish(C_pidout)
                self.DPidoutPub.publish(D_pidout)
            except:
                rospy.logerr("getpidout exception count")
                return

        now = rospy.Time.now()
        if now > self.t_next:
            # Read the encoders
            try:
                aWheel_enc, bWheel_enc, cWheel_enc, dWheel_enc = self.arduino.get_encoder_counts()
            except:
                self.bad_encoder_count += 1
                rospy.logerr("Encoder exception count: " + str(self.bad_encoder_count))
                return
            #rospy.loginfo("Encoder A:"+str(aWheel_enc)+",B:"+str(bWheel_enc)+",C:" + str(cWheel_enc))

            dt = now - self.then
            self.then = now
            dt = dt.to_sec()

            # Calculate odometry
            if self.enc_A == None and self.enc_B == None and self.enc_C == None and self.enc_D == None:
                d_A = 0
                d_B = 0
                d_C = 0
                d_D = 0
            else:
                d_A = (aWheel_enc - self.enc_A) / self.ticks_per_meter
                d_B = (bWheel_enc - self.enc_B) / self.ticks_per_meter
                d_C = (cWheel_enc - self.enc_C) / self.ticks_per_meter
                d_D = (dWheel_enc - self.enc_D) / self.ticks_per_meter

            self.enc_A = aWheel_enc
            self.enc_B = bWheel_enc
            self.enc_C = cWheel_enc
            self.enc_D = dWheel_enc

            va = d_A/dt;
            vb = d_B/dt;
            vc = d_C/dt;
            vd = d_D/dt;
            
			# forward kinematic

            vx = (va + vb + vc + vd) / 4
            vy = (-va + vb - vc + vd) / 4
            vth = (-va - vb + vc + vd) / (4 * self.wheel_track)

            delta_x = (vx * cos(self.th) - vy * sin(self.th)) * dt
            delta_y = (vx * sin(self.th) + vy * cos(self.th)) * dt
            delta_th = vth * dt;

            self.x += delta_x
            self.y += delta_y
            self.th += delta_th

            quaternion = Quaternion()
            quaternion.x = 0.0
            quaternion.y = 0.0
            quaternion.z = sin(self.th / 2.0)
            quaternion.w = cos(self.th / 2.0)
            # Create the odometry transform frame broadcaster.
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
                (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                rospy.Time.now(),
                self.base_frame,
                "odom"
                )
		
            odom = Odometry()
            odom.header.frame_id = "odom"
            odom.child_frame_id = self.base_frame
            odom.header.stamp = now
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
            odom.pose.pose.orientation = quaternion
            
            odom.pose.covariance = [1e-9, 0, 0, 0, 0, 0,
                                    0, 1e-3, 1e-9, 0, 0, 0,
                                    0, 0, 1e6, 0, 0, 0,
                                    0, 0, 0, 1e6, 0, 0,
                                    0, 0, 0, 0, 1e6, 0,
                                    0, 0, 0, 0, 0, 1e-9]
			
            odom.twist.twist.linear.x = vx
            odom.twist.twist.linear.y = vy
            odom.twist.twist.angular.z = vth
            
            odom.twist.covariance = [1e-9, 0, 0, 0, 0, 0,
                                    0, 1e-3, 1e-9, 0, 0, 0,
                                    0, 0, 1e6, 0, 0, 0,
                                    0, 0, 0, 1e6, 0, 0,
                                    0, 0, 0, 0, 1e6, 0,
                                    0, 0, 0, 0, 0, 1e-9]
			
            self.odomPub.publish(odom)

            if now > (self.last_cmd_vel + rospy.Duration(self.timeout)):
                self.v_des_AWheel = 0
                self.v_des_BWheel = 0
                self.v_des_CWheel = 0
                self.v_des_DWheel = 0

            if self.v_A < self.v_des_AWheel:
                self.v_A += self.max_accel
                if self.v_A > self.v_des_AWheel:
                    self.v_A = self.v_des_AWheel
            else:
                self.v_A -= self.max_accel
                if self.v_A < self.v_des_AWheel:
                    self.v_A = self.v_des_AWheel

            if self.v_B < self.v_des_BWheel:
                self.v_B += self.max_accel
                if self.v_B > self.v_des_BWheel:
                    self.v_B = self.v_des_BWheel
            else:
                self.v_B -= self.max_accel
                if self.v_B < self.v_des_BWheel:
                    self.v_B = self.v_des_BWheel

            if self.v_C < self.v_des_CWheel:
                self.v_C += self.max_accel
                if self.v_C > self.v_des_CWheel:
                    self.v_C = self.v_des_CWheel
            else:
                self.v_C -= self.max_accel
                if self.v_C < self.v_des_CWheel:
                    self.v_C = self.v_des_CWheel
                    
            if self.v_D < self.v_des_DWheel:
                self.v_D += self.max_accel
                if self.v_D > self.v_des_DWheel:
                    self.v_D = self.v_des_DWheel
            else:
                self.v_D -= self.max_accel
                if self.v_D < self.v_des_DWheel:
                    self.v_D = self.v_des_DWheel        

            # Set motor speeds in encoder ticks per PID loop
            if not self.stopped:
                self.arduino.drive(self.v_A, self.v_B, self.v_C, self.v_D)
                if self.debugPID:
                    self.AVelPub.publish(self.v_A)
                    self.BVelPub.publish(self.v_B)
                    self.CVelPub.publish(self.v_C)
                    self.CVelPub.publish(self.v_D)

            self.t_next = now + self.t_delta

    def stop(self):
        self.stopped = True
        self.arduino.drive(0, 0, 0, 0)

    def cmdVelCallback(self, req):
        # Handle velocity-based movement requests
        self.last_cmd_vel = rospy.Time.now()

        v_x  = req.linear.x      # m/s
        v_y  = req.linear.y      # m/s
        v_th = req.angular.z     # rad/s

        #reverse kinematic
        vA = v_x - v_y - self.wheel_track * v_th
        vB = v_x + v_y - self.wheel_track * v_th
        vC = v_x - v_y + self.wheel_track * v_th
        vD = v_x + v_y + self.wheel_track * v_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_CWheel = int(vC * self.ticks_per_meter / self.arduino.PID_RATE)
        self.v_des_DWheel = int(vD * self.ticks_per_meter / self.arduino.PID_RATE)
Ejemplo n.º 57
0
class DiffTf:
#############################################################################

    #############################################################################
    def __init__(self):
    #############################################################################
        rospy.init_node("diff_tf")
        self.nodename = rospy.get_name()
        rospy.loginfo("-I- %s started" % self.nodename)
        
        #### parameters #######
        self.rate = rospy.get_param('~rate',10.0)  # the rate at which to publish the transform
        self.ticks_meter = float(rospy.get_param('ticks_meter', 50))  # The number of wheel encoder ticks per meter of travel
        self.base_width = float(rospy.get_param('~base_width', 0.245)) # The wheel base width in meters
 
# emg - base_frame_id should be /robot 
#        self.base_frame_id = rospy.get_param('~base_frame_id','base_link') # the name of the base frame of the robot
        self.base_frame_id = rospy.get_param('~base_frame_id','robot')
        self.odom_frame_id = rospy.get_param('~odom_frame_id', 'odom') # the name of the odometry reference frame
        
        self.encoder_min = rospy.get_param('encoder_min', -32768)
        self.encoder_max = rospy.get_param('encoder_max', 32768)
        self.encoder_low_wrap = rospy.get_param('wheel_low_wrap', (self.encoder_max - self.encoder_min) * 0.3 + self.encoder_min )
        self.encoder_high_wrap = rospy.get_param('wheel_high_wrap', (self.encoder_max - self.encoder_min) * 0.7 + self.encoder_min )
 
        self.t_delta = rospy.Duration(1.0/self.rate)
        self.t_next = rospy.Time.now() + self.t_delta
        
        # internal data
        self.enc_left = None        # wheel encoder readings
        self.enc_right = None
        self.left = 0               # actual values coming back from robot
        self.right = 0
        self.lmult = 0
        self.rmult = 0
        self.prev_lencoder = 0
        self.prev_rencoder = 0
        self.x = 0                  # position in xy plane 
        self.y = 0
        self.th = 0
        self.dx = 0                 # speeds in x/rotation
        self.dr = 0
        self.then = rospy.Time.now()

# emg - adding in a holder for the quaternion
        self.orientation = Quaternion()

        # subscriptions
        rospy.Subscriber("lwheel", Int16, self.lwheelCallback)
        rospy.Subscriber("rwheel", Int16, self.rwheelCallback)
        rospy.Subscriber("Orientation_data", Quaternion, self.orientationCallback)
        self.odomPub = rospy.Publisher("odom", Odometry)
# emg - why the tf_broadcaster? is this the /odom -> /robot? if that's
#       the case, i thought we'd all agreed that these should be
#       explicitly tied together with a static_tf of "0 0 0 0 0 0"
        self.odomBroadcaster = TransformBroadcaster()
        
    #############################################################################
    def spin(self):
    #############################################################################
        r = rospy.Rate(self.rate)
        while not rospy.is_shutdown():
            self.update()
            r.sleep()
       
    #############################################################################
    def update(self):
    #############################################################################
        now = rospy.Time.now()
        if now > self.t_next:
            elapsed = now - self.then
            self.then = now
            elapsed = elapsed.to_sec()
            
            # calculate odometry
            if self.enc_left == None:
                d_left = 0
                d_right = 0
            else:
                d_left = (self.left - self.enc_left) / self.ticks_meter
                d_right = (self.right - self.enc_right) / self.ticks_meter
            self.enc_left = self.left
            self.enc_right = self.right
           
            # distance traveled is the average of the two wheels 
            d = ( d_left + d_right ) / 2
            # this approximation works (in radians) for small angles
            th = ( d_right - d_left ) / self.base_width
            # calculate velocities
            self.dx = d / elapsed
            self.dr = th / elapsed
           
             
            if (d != 0):
                # calculate distance traveled in x and y
                x = cos( th ) * d
                y = -sin( th ) * d
                # calculate the final position of the robot
                self.x = self.x + ( cos( self.th ) * x - sin( self.th ) * y )
                self.y = self.y + ( sin( self.th ) * x + cos( self.th ) * y )
            if( th != 0):
                self.th = self.th + th
            
            #->??? Need to check about race condition with callback?????? later.
            #       it's _possible_ that self.orientation _MIGHT_ change between
            #       references. if it does, it's hopeful that the dt is very very tiny.
            copy_of_orientation = self.orientation

# emg - this is the section that needs to be updated to
#       bring in the IMU orientation
# http://answers.ros.org/question/38099/how-to-subscribe-to-a-topic-at-willon-demand/
# http://answers.ros.org/question/37869/subscribing-and-publishing/
#   in particular, the second one. it explains using spinOnce to
#       block until a message is received and then do other stuff,
#       and then go back to the top of a loop or something. which
#       is essentially what you've done.
# can have two subscribers - one for the wheels, and one for imu.
#   store the imu message in some part of the class and refer to
#   it here.
            # publish the odom information
# emg           quaternion = Quaternion()
# emg           quaternion.x = 0.0
# emg           quaternion.y = 0.0
# emg           quaternion.z = sin( self.th / 2 )
# emg           quaternion.w = cos( self.th / 2 )
            self.odomBroadcaster.sendTransform(
                (self.x, self.y, 0),
# emg               (quaternion.x, quaternion.y, quaternion.z, quaternion.w),
                copy_of_orientation,   # emg - the self-real orientation from /IMU_data
                rospy.Time.now(),
                self.base_frame_id,
                self.odom_frame_id
                )
            
            odom = Odometry()
            odom.header.stamp = now
            odom.header.frame_id = self.odom_frame_id
            odom.pose.pose.position.x = self.x
            odom.pose.pose.position.y = self.y
            odom.pose.pose.position.z = 0
# emg           odom.pose.pose.orientation = quaternion
            odom.pose.pose.orientation = copy_of_orientation   # emg - again
            odom.child_frame_id = self.base_frame_id
            odom.twist.twist.linear.x = self.dx
            odom.twist.twist.linear.y = 0
            odom.twist.twist.angular.z = self.dr
            self.odomPub.publish(odom)
            
            

    #############################################################################
    def orientationCallback(self, msg):
    # emg - catch a wild quaternion
    #############################################################################
        self.orientation = msg

    #############################################################################
    def lwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if (enc < self.encoder_low_wrap and self.prev_lencoder > self.encoder_high_wrap):
            self.lmult = self.lmult + 1
            
        if (enc > self.encoder_high_wrap and self.prev_lencoder < self.encoder_low_wrap):
            self.lmult = self.lmult - 1
            
        self.left = 1.0 * (enc + self.lmult * (self.encoder_max - self.encoder_min)) 
        self.prev_lencoder = enc
        
    #############################################################################
    def rwheelCallback(self, msg):
    #############################################################################
        enc = msg.data
        if(enc < self.encoder_low_wrap and self.prev_rencoder > self.encoder_high_wrap):
            self.rmult = self.rmult + 1
        
        if(enc > self.encoder_high_wrap and self.prev_rencoder < self.encoder_low_wrap):
            self.rmult = self.rmult - 1
            
        self.right = 1.0 * (enc + self.rmult * (self.encoder_max - self.encoder_min))
        self.prev_rencoder = enc
Ejemplo n.º 58
0
class Robot:
   rospy.init_node('omoros', anonymous=True)
   # fetch /global parameters
   param_port = rospy.get_param('~port')
   param_baud = rospy.get_param('~baud')
   param_modelName = rospy.get_param('~modelName')
   
   # Open Serial port with parameter settings
   ser = serial.Serial(param_port, param_baud)
   #ser = serial.Serial('/dev/ttyS0', 115200) #For raspberryPi
   ser_io = io.TextIOWrapper(io.BufferedRWPair(ser, ser, 1),
                           newline = '\r',
                           line_buffering = True)
   config = VehicleConfig()
   pose = MyPose()
   joyAxes = []
   joyButtons = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]    # Buttons 15
   joyDeadband = 0.15
   exp = 0.3            # Joystick expo setting
   isAutoMode = False
   isArrowMode = False  # Whether to control robo with arrow key or not
   arrowCon = ArrowCon
   
   #initialize data
   cmd = Command
   enc_L = 0.0          # Left wheel encoder count from QENCOD message
   enc_R = 0.0          # Right wheel encoder count from QENCOD message
   enc_L_prev = 0.0
   enc_R_prev = 0.0
   enc_offset_L = 0.0
   enc_offset_R = 0.0
   enc_cnt = 0
   odo_L = 0.0          # Left Wheel odometry returned from QODO message
   odo_R = 0.0          # Right Wheel odometry returned from QODO message
   RPM_L = 0.0          # Left Wheel RPM returned from QRPM message
   RPM_R = 0.0          # Right Wheel RPM returned from QRPM message
   speedL = 0.0         # Left Wheel speed returned from QDIFF message
   speedR = 0.0         # Reft Wheel speed returned from QDIFF message
   vel = 0.0            # Velocity returned from CVW command
   rot = 0.0            # Rotational speed returned from CVR command
   def __init__(self):
      ## Set vehicle specific configurations
      if self.param_modelName == "r1":
         print "**********"
         print "Driving R1"
         print "**********"
         self.config.WIDTH = 0.591        # Apply vehicle width for R1 version
         self.config.WHEEL_R = 0.11       # Apply wheel radius for R1 version
         self.config.WHEEL_MAXV = 1200.0  # Maximum speed can be applied to each wheel (mm/s)
         self.config.V_Limit = 0.6        # Limited speed (m/s)
         self.config.W_Limit = 0.1
         self.config.V_Limit_JOY = 0.25   # Limited speed for joystick control
         self.config.W_Limit_JOY = 0.05
         self.config.ArrowFwdStep = 250   # Steps move forward based on Odometry
         self.config.ArrowRotRate = 0.125
         self.config.encoder.Dir = 1.0
         self.config.encoder.PPR = 1000
         self.config.encoder.GearRatio = 15
         
      elif self.param_modelName == "mini":
         print "***************"
         print "Driving R1-mini"
         print "***************"
         self.config.WIDTH = 0.170      # Apply vehicle width for mini version
         self.config.WHEEL_R = 0.0336     # Apply wheel radius for mini version
         self.config.WHEEL_MAXV = 500.0
         self.config.V_Limit = 0.5
         self.config.W_Limit = 0.2
         self.config.V_Limit_JOY = 0.5
         self.config.W_Limit_JOY = 0.1
         self.config.ArrowFwdStep = 100
         self.config.ArrowRotRate = 0.1
         self.config.encoder.Dir = -1.0
         self.config.encoder.PPR = 234
         self.config.encoder.GearRatio = 21         
      else :
         print "Error: param:modelName, Only support r1 and mini. exit..."
         exit()
      print('Wheel Track:{:.2f}m, Radius:{:.2f}m'.format(self.config.WIDTH, self.config.WHEEL_R))
      self.config.BodyCircumference = self.config.WIDTH * math.pi
      print('Platform Rotation arc length: {:04f}m'.format(self.config.BodyCircumference))
      self.config.WheelCircumference = self.config.WHEEL_R * 2 * math.pi
      print('Wheel circumference: {:04f}m'.format(self.config.WheelCircumference))
      self.config.encoder.Step = self.config.WheelCircumference / (self.config.encoder.PPR * self.config.encoder.GearRatio * 4)
      print('Encoder step: {:04f}m/pulse'.format(self.config.encoder.Step))
      
      print(self.ser.name)         # Print which port was really used
      self.joyAxes = [0,0,0,0,0,0,0,0]
      self.joyButtons = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      # Configure data output
      if self.ser.isOpen():
         print("Serial Open")
         self.resetODO()
         sleep(0.05)
         self.reset_odometry()
         self.setREGI(0,'QENCOD')
         sleep(0.05)
         self.setREGI(1,'QODO')
         sleep(0.05)
         self.setREGI(2,'QDIFFV')
         sleep(0.05)
	 self.setREGI(3,'0')
         sleep(0.05)
	 self.setREGI(4,'0')
         #self.setREGI(3,'QVW')
         #sleep(0.05)
         #self.setREGI(4,'QRPM')
         sleep(0.05)
         self.setSPERI(20)
         sleep(0.05)
         self.setPEEN(1)
         sleep(0.05)
         
      self.reset_odometry()   
      # Subscriber
      rospy.Subscriber("joy", Joy, self.callbackJoy)
      rospy.Subscriber("cmd_vel", Twist, self.callbackCmdVel)
      
      # publisher
      self.pub_enc_l = rospy.Publisher('motor/encoder/left', Float64, queue_size=10)
      self.pub_enc_r = rospy.Publisher('motor/encoder/right', Float64, queue_size=10)
      self.pub_motor_status = rospy.Publisher('motor/status', R1MotorStatusLR, queue_size=10)
      self.odom_pub = rospy.Publisher("odom", Odometry, queue_size=10)
      self.odom_broadcaster = TransformBroadcaster()
      
      rate = rospy.Rate(rospy.get_param('~hz', 30)) # 30hz
      rospy.Timer(rospy.Duration(0.05), self.joytimer)
      rospy.Timer(rospy.Duration(0.01), self.serReader)
      self.pose.timestamp = rospy.Time.now()

      while not rospy.is_shutdown():
         if self.cmd.isAlive == True:
             self.cmd.cnt += 1
             if self.cmd.cnt > 1000:         #Wait for about 3 seconds 
                 self.cmd.isAlive = False
                 self.isAutoMode = False
         rate.sleep()
         
      self.ser.close()

   def serReader(self, event):
      reader = self.ser_io.readline()
      if reader:
         packet = reader.split(",")
         try:
            header = packet[0].split("#")[1]
            if header.startswith('QVW'):
               self.vel = int(packet[1])
               self.rot = int(packet[2])
            elif header.startswith('QENCOD'):
               enc_L = int(packet[1])
               enc_R = int(packet[2])
               if self.enc_cnt == 0:
                  self.enc_offset_L = enc_L
                  self.enc_offset_R = enc_R
               self.enc_cnt+=1
               self.enc_L = enc_L*self.config.encoder.Dir - self.enc_offset_L
               self.enc_R = enc_R*self.config.encoder.Dir - self.enc_offset_R
               self.pub_enc_l.publish(Float64(data=self.enc_L))
               self.pub_enc_r.publish(Float64(data=self.enc_R))
               self.pose = self.updatePose(self.pose, self.enc_L, self.enc_R)
               #print('Encoder:L{:.2f}, R:{:.2f}'.format(self.enc_L, self.enc_R))
            elif header.startswith('QODO'):
               self.odo_L = float(packet[1])*self.config.encoder.Dir
               self.odo_R = float(packet[2])*self.config.encoder.Dir
               #print('Odo:{:.2f}mm,{:.2f}mm'.format(self.odo_L, self.odo_R))
            elif header.startswith('QRPM'):
               self.RPM_L = int(packet[1])
               self.RPM_R = int(packet[2])
               #print('RPM:{:.2f}mm,{:.2f}mm'.format(self.RPM_L, self.RPM_R))
            elif header.startswith('QDIFFV'):
               self.speedL = int(packet[1])
               self.speedR = int(packet[2])
         except:
            pass
         status_left = R1MotorStatus(low_voltage = 0, overloaded = 0, power = 0,
                           encoder = self.enc_L, RPM = self.RPM_L, ODO = self.odo_L, speed = self.speedL)
         status_right = R1MotorStatus(low_voltage = 0, overloaded = 0, power = 0,
                           encoder = self.enc_R, RPM = self.RPM_R, ODO = self.odo_R, speed = self.speedR)
         self.pub_motor_status.publish(R1MotorStatusLR(header=Header(stamp=rospy.Time.now()),
                           Vspeed = self.vel, Vomega = self.rot,
                           left=status_left, right=status_right))        

            
   def callbackJoy(self, data):
      self.joyAxes = deepcopy(data.axes)
      #print('Joy:{:.2f},{:.2f}'.format(self.joyAxes[0], self.joyAxes[1]))
      # Read the most recent button state
      newJoyButtons = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      newJoyButtons = deepcopy(data.buttons)
      # Check if button 1(B) is newly set
      if (newJoyButtons[1]==1) and (newJoyButtons[1]!=self.joyButtons[1]):
         if self.isAutoMode!= True:
             self.isAutoMode = True
             print "In Auto mode"
         else:
             self.isAutoMode = False
             print "In Manual mode"
             
      if (newJoyButtons[10]==1) and (newJoyButtons[10]!=self.joyButtons[10]):
         if self.isArrowMode!= True:
             self.isArrowMode = True
             self.arrowCon.isFinished = True
             print "Joystick Arrow Mode"
         else:
             self.isArrowMode = False
             print "Joystick Axis Mode"
      
      if self.isArrowMode == True:
         #if (newJoyButtons[13]==1) or (newJoyButtons[14]==1):
         #if (self.joyAxes[7]==1.0) or (self.joyAxes[7]==-1.0):
         if (self.joyAxes[5]==1.0) or (self.joyAxes[5]==-1.0):
            if self.arrowCon.isFinished ==True:
               self.arrowCon.isFinished = False
               #if newJoyButtons[13]==1:   # FWD arrow
               #if self.joyAxes[7]==1.0:
               if self.joyAxes[5]==1.0:
                  self.arrowCommand("FWD",self.arrowCon,self.config)
               else:
                  self.arrowCommand("REAR",self.arrowCon,self.config)
               #print "Arrow: {:.2f} {:.2f} ".format(self.arrowCon.startOdo_L, self.arrowCon.targetOdo_L)
         #elif (newJoyButtons[11]==1) or (newJoyButtons[12]==1):  #For Xbox360 controller
         #elif (self.joyAxes[6]==1.0) or (self.joyAxes[6]==-1.0):
         elif (self.joyAxes[4]==1.0) or (self.joyAxes[4]==-1.0):
            if self.arrowCon.isFinished ==True:
               turnRate = 10.5
               self.arrowCon.isFinished = False
               #if newJoyButtons[11]==1:   # Left arrow
               #if self.joyAxes[6]==1.0:
               if self.joyAxes[4]==1.0:
                  self.arrowCommand("LEFT",self.arrowCon, self.config)
               else:                     # Right arrow
                  self.arrowCommand("RIGHT",self.arrowCon, self.config)
      # Update button state
      self.joyButtons = deepcopy(newJoyButtons)
      
   def arrowCommand(self, command, arrowCon, config):
      if command == "FWD":
         arrowCon.setFwd = 1
         arrowCon.targetOdo_L = self.odo_L + config.ArrowFwdStep #target 1 step ahead
         arrowCon.targetOdo_R = self.odo_R + config.ArrowFwdStep #target 1 step ahead
         print "Arrow Fwd"
      elif command == "REAR":
         self.arrowCon.setFwd = -1 
         self.arrowCon.targetOdo_L = self.odo_L - self.config.ArrowFwdStep #target 1 step rear
         self.arrowCon.targetOdo_R = self.odo_R - self.config.ArrowFwdStep #target 1 step rear
         print "Arrow Rev"
      elif command == "LEFT":
         arrowCon.setRot = 1
         arrowCon.targetOdo_L = self.odo_L - config.BodyCircumference*1000*config.ArrowRotRate
         arrowCon.targetOdo_R = self.odo_R + config.BodyCircumference*1000*config.ArrowRotRate
         print "Arrow Left"
      elif command == "RIGHT":
         arrowCon.setRot = -1
         arrowCon.targetOdo_L = self.odo_L + config.BodyCircumference*1000*config.ArrowRotRate
         arrowCon.targetOdo_R = self.odo_R - config.BodyCircumference*1000*config.ArrowRotRate
         print "Arrow Right"

         
   def callbackCmdVel(self, cmd):
      """ Set wheel speed from cmd message from auto navigation """
      if self.isAutoMode:
         #print "CMD_VEL: {:.2f} {:.2f} ".format(cmd.linear.x, cmd.angular.z)
         cmdV = cmd.linear.x
         cmdW = cmd.angular.z
         if cmdV>self.config.V_Limit:
            cmdV = self.config.V_Limit
         elif cmdV<-self.config.V_Limit:
            cmdV = -self.config.V_Limit
         if cmdW>self.config.W_Limit:
            cmdW = self.config.W_Limit
         elif cmdW<-self.config.W_Limit:
            cmdW = -self.config.W_Limit
         (speedL,speedR) = self.getWheelSpeedLR(self.config, cmdV, cmdW)
         #print "SPEED LR: {:.2f} {:.2f} ".format(speedL, speedR)
         self.sendCDIFFVcontrol(speedL*200, speedR*200)

   def reset_odometry(self):
      self.last_speedL = 0.0
      self.last_speedR = 0.0

   def joytimer(self, event):
      if not self.isAutoMode:
         self.joy_v = self.joyAxes[1]
         self.joy_w = self.joyAxes[0]
         #print "Joy mode: {:.2f} {:.2f} ".format(self.joy_v, self.joy_w)
      else:
         return
      if not self.isArrowMode:
         # Apply joystick deadband and calculate vehicle speed (mm/s) and rate of chage of orientation(rad/s)
         joyV = 0.0
         joyR = 0.0
         if abs(self.joy_v) < self.joyDeadband:
             joyV = 0.0
         else :
             joyV = (1-self.exp) * self.joy_v + (self.exp) * self.joy_v * self.joy_v * self.joy_v
         if abs(self.joy_w) < self.joyDeadband:
             joyR = 0.0
         else :
             joyR = (1-self.exp) * self.joy_w + (self.exp) * self.joy_w * self.joy_w * self.joy_w
         # Apply max Vehicle speed
         (speedL, speedR) = self.getWheelSpeedLR(self.config, joyV * self.config.V_Limit_JOY, joyR * self.config.W_Limit_JOY)
         #print "Joystick VL, VR: {:.2f} {:.2f}".format(speedL, speedR)
         self.sendCDIFFVcontrol(speedL*1000, speedR*1000)
      else:
         if self.arrowCon.isFinished == False:
            if self.arrowCon.setFwd == 1:  # For forward motion
               if (self.odo_L < self.arrowCon.targetOdo_L) or (self.odo_R < self.arrowCon.targetOdo_R ):
                  #print "Fwd: {:.2f} {:.2f} ".format(self.odo_L, self.odo_R)
                  self.sendCDIFFVcontrol(100, 100)
               else:
                  self.sendCDIFFVcontrol(0, 0)
                  self.arrowCon.isFinished = True
                  self.arrowCon.setFwd = 0
                  print "Finished!"
            elif self.arrowCon.setFwd == -1:
               if (self.odo_L > self.arrowCon.targetOdo_L ) or (self.odo_R > self.arrowCon.targetOdo_R ):
                  #print "Rev: {:.2f} {:.2f} ".format(self.odo_L, self.odo_R)
                  self.sendCDIFFVcontrol(-100, -100)
               else:
                  self.sendCDIFFVcontrol(0, 0)
                  self.arrowCon.isFinished = True
                  self.arrowCon.setFwd = 0
                  print "Finished!"
            elif self.arrowCon.setRot == 1:  #Turning left
               if (self.odo_L > self.arrowCon.targetOdo_L) or (self.odo_R < self.arrowCon.targetOdo_R):
                  #print "Left: {:.2f} {:.2f} ".format(self.odo_L, self.odo_R)
                  self.sendCDIFFVcontrol(-100, 100)
               else:
                  self.sendCDIFFVcontrol(0, 0)
                  self.arrowCon.isFinished = True
                  self.arrowCon.setRot = 0
                  print "Finished!"
            elif self.arrowCon.setRot == -1: #Turning Right
               if (self.odo_L < self.arrowCon.targetOdo_L) or (self.odo_R > self.arrowCon.targetOdo_R):
                  #print "Right: {:.2f} {:.2f} ".format(self.odo_L, self.odo_R)
                  self.sendCDIFFVcontrol(100, -100)
               else:
                  self.sendCDIFFVcontrol(0, 0)
                  self.arrowCon.isFinished = True
                  self.arrowCon.setRot = 0
                  print "Finished!"
                  
   def updatePose(self, pose, encoderL, encoderR):
      """Update Position x,y,theta from encoder count L, R 
      Return new Position x,y,theta"""
      now = rospy.Time.now()
      dL = encoderL - self.enc_L_prev
      dR = encoderR - self.enc_R_prev
      self.enc_L_prev = encoderL
      self.enc_R_prev = encoderR
      dT = (now - pose.timestamp)/1000000.0
      pose.timestamp = now
      x = pose.x
      y = pose.y
      theta = pose.theta
      R = 0.0
      if (dR-dL)==0:
         R = 0.0
      else:
         R = self.config.WIDTH/2.0*(dL+dR)/(dR-dL)
      Wdt = (dR - dL) * self.config.encoder.Step / self.config.WIDTH

      ICCx = x - R * np.sin(theta)
      ICCy = y + R * np.cos(theta)
      pose.x = np.cos(Wdt)*(x - ICCx) - np.sin(Wdt)*(y - ICCy) + ICCx
      pose.y = np.sin(Wdt)*(x - ICCx) + np.cos(Wdt)*(y - ICCy) + ICCy
      pose.theta = theta + Wdt
      
      twist = TwistWithCovariance()
      
      twist.twist.linear.x = self.vel/1000.0
      twist.twist.linear.y = 0.0
      twist.twist.angular.z = self.rot/1000.0
      
      Vx = twist.twist.linear.x
      Vy = twist.twist.linear.y
      Vth = twist.twist.angular.z
      odom_quat = quaternion_from_euler(0,0,pose.theta)
      self.odom_broadcaster.sendTransform((pose.x,pose.y,0.),odom_quat,now,'base_link','odom')
      #self.odom_broadcaster.sendTransform((pose.x,pose.y,0.),odom_quat,now,'base_footprint','odom')
      
      odom = Odometry()
      odom.header.stamp = now
      odom.header.frame_id = 'odom'
      odom.pose.pose = Pose(Point(pose.x,pose.y,0.),Quaternion(*odom_quat))
      
      odom.child_frame_id = 'base_link'
      #odom.child_frame_id = 'base_footprint'
      odom.twist.twist = Twist(Vector3(Vx,Vy,0),Vector3(0,0,Vth))
      print "x:{:.2f} y:{:.2f} theta:{:.2f}".format(pose.x, pose.y, pose.theta*180/math.pi)      
      self.odom_pub.publish(odom)
      return pose

   def getWheelSpeedLR(self, config, V_m_s, W_rad_s):
      """Takes Speed V (m/s) and Rotational sepeed W(rad/s) and compute each wheel speed in m/s        
      Kinematics reference from http://enesbot.me/kinematic-model-of-a-differential-drive-robot.html"""
      speedL = V_m_s - config.WIDTH * W_rad_s / config.WHEEL_R /2.0
      speedR = V_m_s + config.WIDTH * W_rad_s / config.WHEEL_R /2.0
      return speedL, speedR

   def sendCVWcontrol(self, config, V_mm_s, W_mrad_s):
      """ Set Vehicle velocity and rotational speed """
      if V_mm_s > config.V_Limit :
         V_mm_s = config.V_Limit
      elif V_mm_s < -config.V_Limit :
         V_mm_s = -config.V_limit
      if W_mrad_s > config.W_Limit :
         W_mrad_s = config.W_Limit
      elif W_mrad_s < -config.W_Limit:
         W_mrad_s = -config.W_Limit
      # Make a serial message to be sent to motor driver unit
      cmd = '$CVW,{:.0f},{:.0f}'.format(V_mm_s, W_mrad_s)
      print cmd
      if self.ser.isOpen():
         print cmd
         self.ser.write(cmd+"\r"+"\n")

   def sendCDIFFVcontrol(self, VLmm_s, VRmm_s):
      """ Set differential wheel speed for Left and Right """
      if VLmm_s > self.config.WHEEL_MAXV :
         VLmm_s = self.config.WHEEL_MAXV
      elif VLmm_s < -self.config.WHEEL_MAXV :
         VLmm_s = -self.config.WHEEL_MAXV
      if VRmm_s > self.config.WHEEL_MAXV :
         VRmm_s = self.config.WHEEL_MAXV
      elif VRmm_s < -self.config.WHEEL_MAXV :
         VRmm_s = -self.config.WHEEL_MAXV
      # Make a serial message to be sent to motor driver unit
      cmd = '$CDIFFV,{:.0f},{:.0f}'.format(VLmm_s, VRmm_s)
      if self.ser.isOpen():
         #print cmd
         self.ser.write(cmd+"\r"+"\n")
                    
   def setREGI(self, param1, param2):
      msg = "$SREGI,"+str(param1)+','+param2
      self.ser.write(msg+"\r"+"\n")
        
   def setSPERI(self, param):
      msg = "$SPERI,"+str(param)
      self.ser.write(msg+"\r"+"\n")

   def setPEEN(self, param):
      msg = "$SPEEN,"+str(param)
      self.ser.write(msg+"\r"+"\n")
     
   def resetODO(self):
      self.ser.write("$SODO\r\n")
Ejemplo n.º 59
0
class CreateDriver:
	def __init__(self):
		port = rospy.get_param('/irobot/serial_port', "/dev/ttyAMA0")
		self.autodock = rospy.get_param('/irobot/autodock', 0.0)
		self.create = Create(port)
		self.packetPub = rospy.Publisher('sensorPacket', SensorPacket)
		self.odomPub = rospy.Publisher('odom',Odometry)
		self.odomBroadcaster = TransformBroadcaster()
		self.fields = ['wheeldropCaster','wheeldropLeft','wheeldropRight','bumpLeft','bumpRight','wall','cliffLeft','cliffFronLeft','cliffFrontRight','cliffRight','virtualWall','infraredByte','advance','play','distance','angle','chargingState','voltage','current','batteryTemperature','batteryCharge','batteryCapacity','wallSignal','cliffLeftSignal','cliffFrontLeftSignal','cliffFrontRightSignal','cliffRightSignal','homeBase','internalCharger','songNumber','songPlaying']
		self.then = datetime.now() 
		self.x = 0
		self.y = 0
		self.th = 0
		self.create.update = self.sense
		self.docking = False

	def start(self):
		self.create.start()
		self.then = datetime.now() 

	def stop(self):
		self.create.stop()

	def sense(self):
		now = datetime.now()
		elapsed = now - self.then
		self.then = now
		elapsed = float(elapsed.seconds) + elapsed.microseconds/1000000.
		d = self.create.d_distance / 1000.
		th = self.create.d_angle*pi/180
		dx = d / elapsed
		dth = th / elapsed

		if (d != 0):
			x = cos(th)*d
			y = -sin(th)*d
			self.x = self.x + (cos(self.th)*x - sin(self.th)*y)
			self.y = self.y + (sin(self.th)*x + cos(self.th)*y)

		if (th != 0):
			self.th = self.th + th

		quaternion = Quaternion()
		quaternion.x = 0.0 
		quaternion.y = 0.0
		quaternion.z = sin(self.th/2)
		quaternion.w = cos(self.th/2)

		self.odomBroadcaster.sendTransform(
			(self.x, self.y, 0), 
			(quaternion.x, quaternion.y, quaternion.z, quaternion.w),
			rospy.Time.now(),
			"base_link",
			"odom"
			)

		odom = Odometry()
		odom.header.stamp = rospy.Time.now()
		odom.header.frame_id = "odom"
		odom.pose.pose.position.x = self.x
		odom.pose.pose.position.y = self.y
		odom.pose.pose.position.z = 0
		odom.pose.pose.orientation = quaternion

		odom.child_frame_id = "base_link"
		odom.twist.twist.linear.x = dx
		odom.twist.twist.linear.y = 0
		odom.twist.twist.angular.z = dth

		self.odomPub.publish(odom)

		packet = SensorPacket()
		for field in self.fields:
			packet.__setattr__(field,self.create.__getattr__(field))
		self.packetPub.publish(packet)

		charge_level = float(packet.batteryCharge) / float(packet.batteryCapacity)
		if (self.docking and packet.homeBase and charge_level > 0.95):
			self.docking = False
			self.create.reset()
			rospy.sleep(1)
			self.create.start()
		elif (not self.docking and charge_level < self.autodock):
			self.create.demo(1)
			self.docking = True

	def brake(self,req):
		if (req.brake):
			self.create.brake()
		return BrakeResponse(True)

	def circle(self,req):
		if (req.clear):
			self.create.clear()
		self.create.forwardTurn(req.speed,req.radius)
		return CircleResponse(True)

	def demo(self,req):
		self.create.demo(req.demo)
		return DemoResponse(True)

	def leds(self,req):
		self.create.leds(req.advance,req.play,req.color,req.intensity)
		return LedsResponse(True)

	def tank(self,req):
		if (req.clear):
			self.create.clear()
		self.create.tank(req.left,req.right)
		return TankResponse(True)

	def turn(self,req):
		if (req.clear):
			self.create.clear()
		self.create.turn(req.turn)
		return TurnResponse(True)

	def dock(self,req):
		self.create.demo(1)
		self.docking = True
		return DockResponse(True)

	def twist(self,req):
		x = req.linear.x*1000.
		th = req.angular.z
		if (x == 0):
			th = th*180/pi
			speed = (8*pi*th)/9
			self.create.left(int(speed))
		elif (th == 0):
			x = int(x)
			self.create.tank(x,x)
		else:
			self.create.forwardTurn(int(x),int(x/th))