6 from sensor_msgs.msg
import LaserScan
7 from nav_msgs.msg
import Odometry
8 from dynamic_reconfigure.server
import Server
9 import dynamic_reconfigure.client
10 from xaxxon_openlidar.cfg
import XaxxonOpenLidarConfig
18 nominalcycle = 1/(rpm/60.0)
19 dropscan_degpersec = 0
21 rotateforwardoffset = 0
26 dropScanTurnRateThreshold = 0
32 forward_offset = headeroffset
33 park_offset = parkoffset
35 rotate_forward_offset = rotateforwardoffset
39 rebroadcastscan =
None 46 global ser, lidarrunning
53 ser.reset_input_buffer()
56 while ser.inWaiting() > 0:
57 line =
"SCAN: "+ser.readline().strip()
62 rospy.loginfo(
"SCAN: lidar disabled, shutdown");
66 global turning, turnrate, lastodomth, lastodomtime
68 if dropScanTurnRateThreshold == 0:
71 quaternion = ( data.pose.pose.orientation.x, data.pose.pose.orientation.y,
72 data.pose.pose.orientation.z, data.pose.pose.orientation.w )
73 odomth = tf.transformations.euler_from_quaternion(quaternion)[2]
75 now = rospy.get_time()
82 turnrate = (odomth-lastodomth)/(now-lastodomtime)
84 if abs(turnrate) > dropScanTurnRateThreshold:
94 global newheaderoffset, minimum_range, maximum_range
95 global dropScanTurnRateThreshold
96 global forward_offset, rpm_, park_offset, read_frequency, rotate_forward_offset
104 minimum_range = config.minimum_range
105 maximum_range = config.maximum_range
107 dropScanTurnRateThreshold = math.radians(config.dropscan_turnrate)
109 forward_offset = config.forward_offset
111 park_offset = config.park_offset
112 read_frequency = config.read_frequency
113 rotate_forward_offset = config.rotate_forward_offset
114 enable = config.lidar_enable
129 if headeroffset == forward_offset:
132 headeroffset = forward_offset
134 n = int(headeroffset*10)
137 print(
"sending new headeroffset to device: "+str(n))
139 val2 = (n >>8) & 0xFF
168 strmasks = string.split()
170 masks.append(float(s))
172 rospy.logerr(
"error parsing masks")
174 if not (len(masks) % 2) == 0:
175 rospy.logerr(
"uneven number of masks")
182 global rpm, nominalcycle
188 nominalcycle = 1/(rpm/60.0)
191 print(
"sending rpm to device: "+str(rpm))
193 ser.write(
"r"+chr(rpm)+"\n")
199 if parkoffset == park_offset:
202 parkoffset = park_offset
203 n = int(parkoffset*10)
206 print(
"sending parkoffset to device: "+str(parkoffset))
209 val2 = (n >>8) & 0xFF
219 interval = int(1.0/read_frequency*1000000)
220 if interval/1000000.0 == readInterval:
223 readInterval = interval/1000000.0
226 print(
"sending read interval to device: "+str(interval))
228 val1 = interval & 0xFF
229 val2 = (interval >>8) & 0xFF
237 global rotateforwardoffset, masks, headeroffset, forward_offset
239 if rotateforwardoffset == rotate_forward_offset:
243 print(
"setting rotate_forward_offset: "+str(rotate_forward_offset))
246 while i < len(masks):
248 masks[i] += rotateforwardoffset
249 masks[i+1] += rotateforwardoffset
250 if masks[i] >= 360
or masks[i+1] >=360:
255 masks[i] -= rotate_forward_offset
256 masks[i+1] -= rotate_forward_offset
257 if masks[i] < 0
or masks[i+1] < 0:
264 forward_offset -= rotateforwardoffset
265 if forward_offset < 0:
266 forward_offset += 360
269 forward_offset += rotate_forward_offset
270 if forward_offset >= 360:
271 forward_offset -= 360
273 rotateforwardoffset = rotate_forward_offset
278 global lidarrunning, scan, lastscantime, rebroadcastscan
283 rospy.loginfo(
"SCAN: lidar enabled");
286 ser.reset_input_buffer()
289 lastscan = rospy.Time.now()
295 consecutivescandropped = 0
297 while not rospy.is_shutdown()
and ser.is_open
and enable:
308 rospy.logerr(
"no response from xaxxonlidar device")
318 if rebroadcastscan
and BROADCASTLAST:
321 if not ord(ch) == 0xFF:
326 if not ord(ch) == 0xFF:
331 if not ord(ch) == 0xFF:
336 if not ord(ch) == 0xFF:
342 low = ord(ser.read(1))
343 high = ord(ser.read(1))
344 count = (high<<8)|low
347 c1 = ord(ser.read(1))
348 c2 = ord(ser.read(1))
349 c3 = ord(ser.read(1))
350 c4 = ord(ser.read(1))
351 cycle = ((c4<<24)|(c3<<16)|(c2<<8)|c1)/1000000.0
354 current_time = rospy.Time.now()
355 rospycycle = current_time - lastscan
357 lastscan = current_time
359 rospycount = (len(raw_data)-headercodesize)/2
364 """ error monitoring, debug info """ 367 if DEBUGOUTPUT
and scannum % 10 == 0:
368 msg =
"SCAN "+str(scannum)+
": cycle: "+str(cycle)+
", count: "+str(count)
372 if not rospycount == count
and scannum > 1
and DEBUGOUTPUT:
373 msg =
"SCAN "+str(scannum)+
": count/data mismatch: "+ str( rospycount-count )
377 if abs(count - lastcount) > 2
and scannum > 4
and DEBUGOUTPUT:
378 msg =
"SCAN "+str(scannum)+
": count change from: "+ str(lastcount)+
", to: "+str(count)
383 if count<(nominalcycle/readInterval/2)
and scannum > 4:
385 msg =
"SCAN "+str(scannum)+
": low data count: "+str(count)+
", cycle: "+str(cycle)
386 msg +=
", scan dropped" 389 if consecutivescandropped > 3:
390 rospy.logerr(
"resetting device")
398 consecutivescandropped += 1
402 consecutivescandropped = 0
411 rebroadcastscan =
None 415 scan.header.stamp = current_time - rospy.Duration(cycle)
416 lastscantime = current_time.to_sec() - cycle
418 scan.header.frame_id = frameID
422 scan.angle_max = (readInterval*(count-1))/rpmcycle * 2 * math.pi
423 scan.angle_increment = (scan.angle_max-scan.angle_min) / (count-1)
425 scan.time_increment = readInterval
426 scan.scan_time = readInterval * count
428 scan.range_min = minimum_range
429 scan.range_max = maximum_range
433 for x
in range(len(raw_data)-(count*2)-headercodesize, len(raw_data)-headercodesize, 2):
434 low = ord(raw_data[x])
435 high = ord(raw_data[x+1])
436 value = ((high<<8)|low) / 100.0
437 scan.ranges.append(value)
439 """ blank frame masks W/RHR+ degrees start, stop """ 441 while i < len(masks):
442 for x
in range(int(count*((masks[i])/360.0)), int(count*((masks[i+1])/360.0)) ):
446 """ if blanking scans when turning """ 448 for i
in range(len(scan.ranges)):
453 scan_pub.publish(scan)
458 global lastscantime, rebroadcastscan
460 if lastscantime <= (rospy.get_time() - nominalcycle*2):
461 lastscantime += nominalcycle
462 rebroadcastscan.header.stamp = rospy.Time.from_sec(lastscantime)
463 scan_pub.publish(rebroadcastscan)
468 rospy.init_node(
'lidarbroadcast', anonymous=
False)
469 rospy.on_shutdown(cleanup)
470 scan_pub = rospy.Publisher(rospy.get_param(
'~scan_topic',
'scan'), LaserScan, queue_size=3)
471 rospy.Subscriber(
"odom", Odometry, odomCallback)
472 frameID = rospy.get_param(
'~frame_id',
'laser_frame')
474 Server(XaxxonOpenLidarConfig, dynamicConfigCallback)
475 client = dynamic_reconfigure.client.Client(
"lidarbroadcast", timeout=30)
479 if ser ==
None and not rospy.is_shutdown():
480 ser = device.usbdiscover(
"<id::xaxxonopenlidar>", 5)
484 while ser.inWaiting() > 0:
485 line = ser.readline().strip()
486 line =
"firmware: "+line
488 ser.write(
"d"+chr(DIR)+
"\n")
504 rospy.loginfo(
"SCAN: lidar disabled");
505 rebroadcastscan = scan
506 elif rebroadcastscan
and BROADCASTLAST:
510 if rospy.is_shutdown():
513 device.removelockfile()
def updateRotateForwardOffset()
def dynamicConfigCallback(config, level)