Removing the 3D code from this script so that it produces 2D scatterplot

37 views
Skip to first unread message

ZebrasHaveTails

unread,
Aug 16, 2016, 11:16:01 PM8/16/16
to VPython-users
Dear All

Here is an interesting question for you 3D experts. How might I remove the 3D code in this script so that it simply presents a 2D graph of the coordinates on a scatterplot? Apologies if I seem dumb but I am a complete novice at python and I would like some help to get going. 

I have asked another question on the forum about how to use vpython on a raspberry pi 3 model b as well by the way ... so I am exploring both possibilities.I would actually be happy though to simply have a 2D plot of the outcome.

Thanks!

Regards Z 



#Display Data from Neato LIDAR
#based on code from Nicolas "Xevel" Saugnier
#requires vpython and pyserial


import thread, time, sys, traceback, math

com_port = "COM4" # example: 5 == "COM6" == "/dev/tty5"
baudrate = 115200
visualization = True

offset = 140
init_level = 0
index = 0

lidarData = [[] for i in range(360)] #A list of 360 elements Angle, Distance , quality


if visualization:
    from visual import *
# sample and intensity points
    point = points(pos=[(0,0,0) for i in range(360)], size=5, color=(0 , 1, 0))
    pointb = points(pos=[(0,0,0) for i in range(360)], size=5, color=(0.4, 0, 0))
    point2 = points(pos=[(0,0,0) for i in range(360)], size=3, color=(1 , 1, 0))
    point2b = points(pos=[(0,0,0) for i in range(360)], size=3, color=(0.4, 0.4, 0))
    #lines
    outer_line= curve (pos=[(0,0,0) for i in range(360)], size=5, color=(1 , 0, 0))
    lines=[curve(pos=[(offset*cos(i* pi / 180.0),0,offset*-sin(i* pi / 180.0)),(offset*cos(i* pi / 180.0),0,offset*-sin(i* pi / 180.0))], color=[(0.1, 0.1, 0.2),(1,0,0)]) for i in range(360)]
    zero_intensity_ring = ring(pos=(0,0,0), axis=(0,1,0), radius=offset-1, thickness=1, color = color.yellow)

    label_speed = label(pos = (0,-500,0), xoffset=1, box=False, opacity=0.1)
    label_errors = label(pos = (0,-1000,0), xoffset=1, text="errors: 0", visible = False, box=False)

use_points = True
use_outer_line = False
use_lines = False
use_intensity = True

def update_view( angle, data ):
    """Updates the view of a sample.

Takes the angle (an int, from 0 to 359) and the list of four bytes of data in the order they arrived.
"""
    global offset, use_outer_line, use_line
    #unpack data using the denomination used during the discussions
    x = data[0]
    x1= data[1]
    x2= data[2]
    x3= data[3]
    
    angle_rad = angle * math.pi / 180.0
    c = math.cos(angle_rad)
    s = -math.sin(angle_rad)

    dist_mm = x | (( x1 & 0x3f) << 8) # distance is coded on 13 bits ? 14 bits ?
    quality = x2 | (x3 << 8) # quality is on 16 bits
    lidarData[angle] = [dist_mm,quality]
    dist_x = dist_mm*c
    dist_y = dist_mm*s
    if visualization:
        #reset the point display
        point.pos[angle] = vector( 0, 0, 0 )
        pointb.pos[angle] = vector( 0, 0, 0 )
        point2.pos[angle] = vector( 0, 0, 0 )
        point2b.pos[angle] = vector( 0, 0, 0 )
        if not use_lines : lines[angle].pos[1]=(offset*c,0,offset*s)
        if not use_outer_line :
            outer_line.pos[angle]=(offset*c,0,offset*s)
            outer_line.color[angle] = (0.1, 0.1, 0.2)
        
        
        # display the sample
        if x1 & 0x80: # is the flag for "bad data" set?
            # yes it's bad data
            lines[angle].pos[1]=(offset*c,0,offset*s)
            outer_line.pos[angle]=(offset*c,0,offset*s)
            outer_line.color[angle] = (0.1, 0.1, 0.2)
        else:
            # no, it's cool
            if not x1 & 0x40:
                # X+1:6 not set : quality is OK
                if use_points : point.pos[angle] = vector( dist_x,0, dist_y)
                if use_intensity : point2.pos[angle] = vector( (quality + offset)*c,0, (quality + offset)*s)
                if use_lines : lines[angle].color[1] = (1,0,0)
                if use_outer_line : outer_line.color[angle] = (1,0,0)
            else:
                # X+1:6 set : Warning, the quality is not as good as expected
                if use_points : pointb.pos[angle] = vector( dist_x,0, dist_y)
                if use_intensity : point2b.pos[angle] = vector( (quality + offset)*c,0, (quality + offset)*s)
                if use_lines : lines[angle].color[1] = (0.4,0,0)
                if use_outer_line : outer_line.color[angle] = (0.4,0,0)
            if use_lines : lines[angle].pos[1]=( dist_x, 0, dist_y)
            if use_outer_line : outer_line.pos[angle]=( dist_x, 0, dist_y)




def checksum(data):
    """Compute and return the checksum as an int.

data -- list of 20 bytes (as ints), in the order they arrived in.
"""
    # group the data by word, little-endian
    data_list = []
    for t in range(10):
        data_list.append( data[2*t] + (data[2*t+1]<<8) )
    
    # compute the checksum on 32 bits
    chk32 = 0
    for d in data_list:
        chk32 = (chk32 << 1) + d

    # return a value wrapped around on 15bits, and truncated to still fit into 15 bits
    checksum = (chk32 & 0x7FFF) + ( chk32 >> 15 ) # wrap around to fit into 15 bits
    checksum = checksum & 0x7FFF # truncate to 15 bits
    return int( checksum )


def gui_update_speed(speed_rpm):
    label_speed.text = "RPM : " + str(speed_rpm)

def compute_speed(data):
    speed_rpm = float( data[0] | (data[1] << 8) ) / 64.0
    return speed_rpm

def read_Lidar():
    global init_level, angle, index
    
    nb_errors = 0
    while True:
        try:
            time.sleep(0.00001) # do not hog the processor power

            if init_level == 0 :
                b = ord(ser.read(1))
                # start byte
                if b == 0xFA :
                    init_level = 1
                    #print lidarData
                else:
                    init_level = 0
            elif init_level == 1:
                # position index
                b = ord(ser.read(1))
                if b >= 0xA0 and b <= 0xF9 :
                    index = b - 0xA0
                    init_level = 2
                elif b != 0xFA:
                    init_level = 0
            elif init_level == 2 :
                # speed
                b_speed = [ ord(b) for b in ser.read(2)]
                
                # data
                b_data0 = [ ord(b) for b in ser.read(4)]
                b_data1 = [ ord(b) for b in ser.read(4)]
                b_data2 = [ ord(b) for b in ser.read(4)]
                b_data3 = [ ord(b) for b in ser.read(4)]

                # for the checksum, we need all the data of the packet...
                # this could be collected in a more elegent fashion...
                all_data = [ 0xFA, index+0xA0 ] + b_speed + b_data0 + b_data1 + b_data2 + b_data3

                # checksum
                b_checksum = [ ord(b) for b in ser.read(2) ]
                incoming_checksum = int(b_checksum[0]) + (int(b_checksum[1]) << 8)

                # verify that the received checksum is equal to the one computed from the data
                if checksum(all_data) == incoming_checksum:
                    speed_rpm = compute_speed(b_speed)
                    if visualization:
                        gui_update_speed(speed_rpm)
                    
                    update_view(index * 4 + 0, b_data0)
                    update_view(index * 4 + 1, b_data1)
                    update_view(index * 4 + 2, b_data2)
                    update_view(index * 4 + 3, b_data3)
                else:
                    # the checksum does not match, something went wrong...
                    nb_errors +=1
                    if visualization:
                        label_errors.text = "errors: "+str(nb_errors)
                    
                    # display the samples in an error state
                    update_view(index * 4 + 0, [0, 0x80, 0, 0])
                    update_view(index * 4 + 1, [0, 0x80, 0, 0])
                    update_view(index * 4 + 2, [0, 0x80, 0, 0])
                    update_view(index * 4 + 3, [0, 0x80, 0, 0])
                    
                init_level = 0 # reset and wait for the next packet
                
            else: # default, should never happen...
                init_level = 0
        except :
            traceback.print_exc(file=sys.stdout)

def checkKeys():
    global use_outer_line, use_lines, use_points, use_intensity
    if scene.kb.keys: # event waiting to be processed?
        s = scene.kb.getkey() # get keyboard info

        if s=="o": # Toggle outer line
            use_outer_line = not use_outer_line
        elif s=="l": # Toggle rays
            use_lines = not use_lines
        elif s=="p": # Toggle points
            use_points = not use_points
        elif s=="i": # Toggle intensity
            use_intensity = not use_intensity
            zero_intensity_ring.visible = use_intensity

        elif s=="n": # Toglle lidar representation
            lidar.visible = not lidar.visible

        elif s=="j": # Toggle rpm
            label_speed.visible = not label_speed.visible
        elif s=="k": # Toggle errors
            label_errors.visible = not label_errors.visible


import serial
ser = serial.Serial(com_port, baudrate)
th = thread.start_new_thread(read_Lidar, ())

while True:
    if visualization:
        rate(60) # synchonous repaint at 60fps
        checkKeys()
    

Bruce Sherwood

unread,
Aug 17, 2016, 1:44:23 AM8/17/16
to VPython-users
It's impossible to learn anything about the Raspberry problem with such a complex program as this as the test case. A suitable test program is this:

from vpython import *
box()

Chris Jackson

unread,
Aug 17, 2016, 2:05:37 AM8/17/16
to vpytho...@googlegroups.com
Thanks Bruce. Now I regret having 2 threads open.

Anyway, I suppose I just have a specific "dream" about getting this particular python script going on my raspberry which is why I am focussing on it even though it is clearly relatively complex and beyond my present knowledge of python. 

Anyway without a successful installation of vpython on my raspberry pi 3, the simple script still will not work but I will try it on my pc.

Many thanks!

Thanks



--
You received this message because you are subscribed to a topic in the Google Groups "VPython-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/vpython-users/cx4gfS88D8g/unsubscribe.
To unsubscribe from this group and all its topics, send an email to vpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages