0
$\begingroup$

I am writing a ROS node to read CAN data (linear x speed, and direction of motion i.e. rev or fwd) from my vehicle and my steer-by-wire system (encoder data for angular z). Both CAN interfaces are on separate CAN bus. I am using that data to generate odometry. We will call this node odom node.The odom node has 2 threads : one thread to generate linear velocity and another one to generate angular z velocity. The node also has a publisher for each of those parameters as well.

I also have a planning algorithm that works fine without the odom node, however, when I run my planning algorithm with my odom node, the planning algorithm crashes.

I opened up htop to see if its some sort of memory issue, I noticed that while the odom node is running, the number of threads keep on increasing (please refer to the image attached, 10740 threads).

htop I am not sure why the number of threads keep increasing, since Python has GIL, the first thread should get terminated before the second one is started. Could someone please help me figure out what am I doing wrong?

Code :

#!/usr/bin/env python3

import cantools
import can
from pprint import pprint
import rospy
from geometry_msgs.msg import Twist 
import numpy as np
import fixedint
import std_msgs.msg
from std_msgs.msg import Float64
from nav_msgs.msg import Odometry 
import math
import threading
import unittest

db = cantools.database.load_file('dbc_files/kia.dbc')
vehicle_can_bus = can.interface.Bus('can0', bustype='socketcan')
steer_by_wire_can_bus = can.interface.Bus('can1', bustype="socketcan")

class Telemetry:
    
    def __init__(self, linear_x, angular_z, encoder_angle,direction):

        self.linear_x = linear_x 
        self.angular_z = angular_z
        self.encoder_angle = encoder_angle
        self.direction = direction
   
        try : 

            self.linear_rate = rospy.get_param('~linear_vel_rate')
            self.angular_rate = rospy.get_param('~angular_vel_rate')

        except KeyError:
            print ("Could not set angular and linear thread rate parameters!!!")


        rospy.Timer(rospy.Duration(1.0 / self.linear_rate), self.linear_velocity_loop)
        rospy.Timer(rospy.Duration(1.0 / self.angular_rate), self.angular_velocity_loop)


    def linear_velocity_loop(self,event): 

        while not rospy.is_shutdown() : 

            # reader = can.BufferedReader()
            # notifier = can.Notifier(vehicle_can_bus, [reader], 10) # bus, listeners, time
            # message = reader.get_message(10) # timeout
            # if (message.arbitration_id == 213786525):
            #     rospy.loginfo_throttle((1/10),message.arbitration_id)

            message = vehicle_can_bus.recv()


            if message.arbitration_id == 317284680: # ID of ShtlDisp
                 # this message will print every 0.05 seconds (1/20)
                rospy.loginfo_throttle((1/10), "Shuttle msg")
                shuttle_data = db.decode_message('ShtlDisp', message.data)
                ShtlSymbol = shuttle_data['ShtlSymbol']
               
                if (ShtlSymbol == 3) :  # if the shuttle is in rev position, ShtlSymbol == 1 is fwd, 2 is neutral, 3 is rev
                    self.direction  = -1
                    # rospy.loginfo("The shuttle status is reverse")

                elif ShtlSymbol == 1 :
                    self.direction  = 1
                    # rospy.loginfo("The shuttle status is forward")

                # else:
                    # self.direction  = 0
                    # rospy.loginfo("The shuttle status is neutral")
                    

            if message.arbitration_id == 213786525: # ID converted to HEX. Make sure if CAN ID is 19 or 29 bit. ID of DbmSpeedDisplay 213786525

                rospy.loginfo_throttle((1/10), "Received speed from CAN")

                readable_data = db.decode_message('DbmSpeedDisplay', message.data)
                SpeedDisplay_H = readable_data['SpeedDisplay_H']
                SpeedDecimalPoint = readable_data['SpeedDecimalPoint']
                SpeedDisplay_L = readable_data['SpeedDisplay_L'] # to kmph (dib by 100) and then m/sec (div 3.6)
                PtoRpm_H = readable_data['PtoRpm_H']
                PtoRpm_L = readable_data['PtoRpm_L']


                if (SpeedDisplay_H == 0): 
                    if (SpeedDisplay_L < 0):
                        SpeedDisplay_L =  255 + SpeedDisplay_L

                if (SpeedDisplay_H == 1): 
                    if (SpeedDisplay_L > 0):
                        SpeedDisplay_L =  255 + SpeedDisplay_L

                velocity = SpeedDisplay_L*self.direction
                self.linear_x = velocity/(100*3.6) # 3.6 to kmph >> m/s and div by 100 to chnage from 116 m/h (from CAN) to 1.16 kmph

            # while not reader.buffer.empty(): 
            #        reader.buffer.get()


    def angular_velocity_loop(self,event):

        while not rospy.is_shutdown() : 

            dbw_reader = can.BufferedReader()
            dbw_notifier = can.Notifier(steer_by_wire_can_bus, [dbw_reader], 0.1) # bus, listeners, time
            encoder_message = dbw_reader.get_message(0.1) # timeout

            # encoder_message = steer_by_wire_can_bus.recv()
            
            if encoder_message and encoder_message.arbitration_id == 1:

                #rospy.loginfo_throttle (duration (n), message) # publish the message every n seconds 
            
                rospy.loginfo_throttle((1/10), "Recieved Encoder Data") # this message will print every 0.05 seconds (1/20)
     
                encoder_data = np.uint16(encoder_message.data)

                xx = encoder_data[3] | (encoder_data[4] << 8)

                xx &= 0x0FFF

                if xx & 0x0800:
                    xx |= 0xF000
                
                angle = np.int16(xx) * (-360.0 / 4096.0)

                if angle > 0.0:
                    angle *= 1.21582733812
            
                angle =  angle *(3.14/180)

                self.encoder_angle = angle

                # angular speed (z) calculation
                wheelbase =  rospy.get_param('~wheelbase')
                self.angular_z = self.linear_x * math.tan(self.encoder_angle)/wheelbase

                # rospy.sleep(rospy.Duration(2))

                # clear CAN message buffer to always get the latest message 

                while not dbw_reader.buffer.empty(): 
                   dbw_reader.buffer.get()
                    
                

def telematics_publish(telemetry):

    pub = rospy.Publisher('/vehicle_telematics/odom', Odometry, queue_size=10)
    encoder_pub = rospy.Publisher('/vehicle_telematics/encoder', Float64, queue_size=10)


    try: 
        pub_rate = rospy.get_param('~publishing_rate')
        rate = rospy.Rate(pub_rate)
    except KeyError:
        rospy.logerr("Could not set publishing rate !!!")

    # rate = rospy.Rate(10)

    twist = Twist() 
    odom = Odometry()

    while not rospy.is_shutdown(): 

        odom.header.stamp = rospy.Time.now()
        odom.header.frame_id = 'base_odom'

        odom.pose.pose.position.x = 0
        odom.pose.pose.position.y = 0
        odom.pose.pose.position.z = 0.0

        odom.pose.pose.orientation.x = 0
        odom.pose.pose.orientation.y = 0
        odom.pose.pose.orientation.z = 0
        odom.pose.pose.orientation.w = 0

        odom.child_frame_id = "odom"
        odom.twist.twist.linear.x = telemetry.linear_x
        odom.twist.twist.linear.y = 0
        odom.twist.twist.angular.z = telemetry.angular_z

        # rospy.loginfo(odom)
        # rospy.loginfo(telemetry.encoder_angle)

        pub.publish(odom)
        rospy.loginfo_throttle((1/10), "Odom published")

        encoder_pub.publish(telemetry.encoder_angle)
        rospy.loginfo_throttle((1/10), "Encoder published") # if rospy.loginfo seems to slow the node down then change 1/rate to 1/10. 1/20 seems to work great for all rospy.loginfo in this code.
        rate.sleep()


if __name__ == '__main__':
    try:
        rospy.init_node('vehicle_telematics')

        tele = Telemetry(0,0,0,1)
        
        telematics_publish(tele)

    except rospy.ROSInterruptException:
        pass
$\endgroup$
1
  • $\begingroup$ Please try to reduce your code snippets to the minimum amount possible to reduce the complexity. And even better would be too make it self contained so your problem could be reproduced. $\endgroup$
    – Tully
    Commented Nov 28, 2022 at 21:58

1 Answer 1

0
$\begingroup$

I can't reproduce your problem due to unspecified dependencies and other steps needed.

But looking at you code, you appear to have loops that go infinity (while not rospy.is_shutdown()) being started periodically (rospy.Timer(rospy.Duration(1.0 / self.angular_rate), self.angular_velocity_loop))

Depending on what's in those loops it seems like it would potentially produce more and more threads.

$\endgroup$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.