1
import hdbscan
import rospy
from rospy.core import rospyinfo
from sensor_msgs.msg import PointCloud, PointCloud2
import numpy as np
import pcl
import ros_numpy
import time
from hdbscan_py.msg import cluster_list


   
rospy.init_node('hdbscan')

#This is utilizing the data to cluster
def callback(data):
    tstart = time.time()
    pc = ros_numpy.numpify(data)
    points=np.zeros((pc.shape[0], 3))
    points[:,0]=pc['x']
    points[:,1]=pc['y']
    points[:,2]=pc['z']
    p = pcl.PointCloud(np.array(points, dtype=np.float32))
    
    #Utilizes PointCloud points generated to passthrough HDBSCAN
    clusterer = hdbscan.HDBSCAN(min_cluster_size=15, min_samples=1, alpha=1.3).fit(p)
    cluster_labels = clusterer.fit_predict(p)
    #cluster_cloud = pcl.PointCloud_PointXYZRGB()

    #cloudpoints = 
    #rospy.loginfo(cluster_labels)
    tstop = time.time()
    
    talker(cluster_labels, p)
    rospy.loginfo(tstop-tstart)

   

def talker(cluster_labels, p):
    pubClusters = rospy.Publisher('clusters', cluster_list, queue_size=1)
    cluster_list_msg=cluster_list()
    #cluster=[]
    for cluster_index in range(np.size(p)):
        cluster_list_msg[cluster_labels[cluster_index]].append(p[cluster_index])
    
    rospy.loginfo('Test')
    pubClusters.publish(cluster_list_msg)
    #pub.publish(clusters_msg)

#This is subscribing to the sensor data
def listener():
    rospy.Subscriber('/wamv/sensors/lidars/lidar_wamv/points', PointCloud2, callback)
    rospy.spin()

if __name__=='__main__':
    listener()

=========================================================================================

The following code is my hdbscan script written in python. I have even created a custom message to create a cluster[] as cluster_list however, when I try passing the data through I get an error which I will provide a below:

I am using barebones hdbscan package untuned just to determine the clustering accuracy and if it is at all usable for a surface vehicle. Not sure if maybe my approach is incorrect as I am relatively new to ROS. If anyone has tips let me know please.

Output Error:

[ERROR] [1638060785.496382]: bad callback: <function callback at 0x7f0ba5401430>
Traceback (most recent call last):
  File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 750, in _invoke_callback
    cb(msg)
  File "dbscan_lidar.py", line 34, in callback
    talker(cluster_labels, p)
  File "dbscan_lidar.py", line 44, in talker
    cluster_list_msg[cluster_labels[cluster_index]].append(p[cluster_index])
TypeError: 'cluster_list' object is not subscriptable
BTables
  • 4,413
  • 2
  • 11
  • 30
Drizzy23
  • 21
  • 1

1 Answers1

0

Since it is still a ROS message you need to reference the fields directly. Much like how a UInt8MultiArray does not support [] directly, you need to use msg.data[]. You should be appending to an attribute of the object, not index it directly. Without seeing the exact definition of cluster_list it's impossible to say what the exact syntax is, but it should look like this assuming the message contains cluster[]

cluster_list_msg=cluster_list()
    #cluster=[]
    for cluster_index in range(np.size(p)):
        cluster_list_msg.cluster.append(p[cluster_index])

Another note to keep in mind is where pubClusters is defined. If a function is called more than one time the publisher should not be created for every call. Instead define it as an attribute in __init__ and just reference that every time it is needed.

BTables
  • 4,413
  • 2
  • 11
  • 30
  • Where can I look into the syntax for using __init__? also if I want to visualize the Pointclouds I have converted from PC2, would I use pcl::toRosmsg()? or is there a better method? – Drizzy23 Nov 29 '21 at 20:37
  • @Drizzy23 I'm not sure what you specifically mean by using init. That might warrant creating a new question with further details. But yes, to visualize in `rviz` you should use `pcl::toRosmsg()`, publish that message, and subscribe to the topic in `rviz` – BTables Nov 29 '21 at 20:41