Esempio n. 1
0
def collect(chatter):
    msg = yield marv.pull(chatter)
    assert msg is not None
    yield marv.push(msg.data)
    while True:
        msg = yield marv.pull(chatter)
        if msg is None:
            return
        yield marv.push(msg.data)
Esempio n. 2
0
def orientations(imus, navsatorients):
    while True:
        tmp = yield marv.pull(imus)
        if tmp is None:
            break
        yield marv.push(tmp)
    while True:
        tmp = yield marv.pull(navsatorients)
        if tmp is None:
            break
        yield marv.push(tmp)
Esempio n. 3
0
def meta_table(dataset):
    dataset = yield marv.pull(dataset)
    columns = [
        {
            'title': 'Name',
            'formatter': 'rellink'
        },
        {
            'title': 'Size',
            'formatter': 'filesize'
        },
    ]
    # dataset.id is setid here
    rows = [{
        'id':
        idx,
        'cells': [
            {
                'link': {
                    'href': '{}'.format(idx),
                    'title': os.path.basename(f.path)
                }
            },
            {
                'uint64': f.size
            },
        ]
    } for idx, f in enumerate(dataset.files)]
    yield marv.push({'table': {'columns': columns, 'rows': rows}})
Esempio n. 4
0
def navsatfix(stream):
    yield marv.set_header(title=stream.topic)
    pytype = get_message_type(stream)
    rosmsg = pytype()
    erroneous = 0
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            break
        rosmsg.deserialize(msg.data)
        if not hasattr(rosmsg, 'status') or \
           np.isnan(rosmsg.longitude) or \
           np.isnan(rosmsg.latitude) or \
           np.isnan(rosmsg.altitude):
            erroneous += 1
            continue
        # TODO: namedtuple?
        out = {
            'status': rosmsg.status.status,
            'lon': rosmsg.longitude,
            'lat': rosmsg.latitude,
            'timestamp': rosmsg.header.stamp.to_time()
        }
        yield marv.push(out)
    if erroneous:
        log = yield marv.get_logger()
        log.warn('skipped %d erroneous messages', erroneous)
Esempio n. 5
0
def connections_section(bagmeta, dataset, title):
    """Section displaying information about ROS connections."""
    dataset, bagmeta = yield marv.pull_all(dataset, bagmeta)
    if not bagmeta.topics:
        raise marv.Abort()
    columns = [
        {'title': 'Topic'},
        {'title': 'Type'},
        {'title': 'MD5'},
        {'title': 'Latching'},
        {'title': 'Message count', 'align': 'right'}
    ]
    rows = [{'id': idx, 'cells': [
        {'text': con.topic},
        {'text': con.datatype},
        {'text': con.md5sum},
        {'bool': con.latching},
        {'uint64': con.msg_count}
    ]} for idx, con in enumerate(bagmeta.connections)]
    widgets = [{'table': {'columns': columns, 'rows': rows}}]
    # TODO: Add text widget explaining what can be seen here: ROS bag
    # files store connections. There can be multiple connections for
    # one topic with the same or different message types and message
    # types with the same name might have different md5s. For
    # simplicity connections with the same topic, message type and md5
    # are treated as one, within one bag file as well as across bags
    # of one set. If one of such connections is latching, the
    # aggregated connection will be latching.
    yield marv.push({'title': title, 'widgets': widgets})
Esempio n. 6
0
def filesize_plot_fixed(filesizes):
    # set_header() helps marv to schedule nodes
    yield marv.set_header()

    # Pull all filesizes
    sizes = []
    while True:
        size = yield marv.pull(filesizes)
        if size is None:
            break
        sizes.append(size)

    # plot
    fig = plt.figure()
    axis = fig.add_subplot(1, 1, 1)
    axis.plot(sizes, 'bo')
    #axis.set_xlabel('foo')
    #axis.set_ylabel('bat')

    # save figure to file
    plotfile = yield marv.make_file('filesizes.json')
    with open(plotfile.path, 'w') as f:
        json.dump(mpld3.fig_to_dict(fig), f)

    # create plot widget referencing file
    widget = {
        'title': 'Filesizes',
        'mpld3': 'marv-partial:{}'.format(plotfile.relpath),
    }
    yield marv.push(widget)
Esempio n. 7
0
def filesize_plot(filesizes):
    # Pull all filesizes
    sizes = []
    while True:
        size = yield marv.pull(filesizes)
        if size is None:
            break
        sizes.append(size)

    # plot
    fig = plt.figure()
    axis = fig.add_subplot(1, 1, 1)
    axis.plot(sizes, 'bo')

    # EE: save figure to file
    plotfile = yield marv.make_file('filesizes.json')
    with open(plotfile.path, 'w') as f:
        json.dump(mpld3.fig_to_dict(fig), f)

    # EE: create plot widget referencing file
    widget = {
        'title': 'Filesizes',
        'mpld3': 'marv-partial:{}'.format(plotfile.relpath),
    }

    # Alternative code for community edition
    #plotfile = yield marv.make_file('filesizes.jpg')
    #fig.savefig(plotfile.path)
    #widget = {
    #    'title': 'Filesizes',
    #    'image': {'src': plotfile.relpath},
    #}

    yield marv.push(widget)
Esempio n. 8
0
def summary_keyval(dataset):
    dataset = yield marv.pull(dataset)
    if len(dataset.files) < 2:
        return
    yield marv.push({
        'keyval': {
            'items': [
                {
                    'title': 'size',
                    'formatter': 'filesize',
                    'list': False,
                    'cell': {
                        'uint64': sum(x.size for x in dataset.files)
                    }
                },
                {
                    'title': 'files',
                    'list': False,
                    'cell': {
                        'uint64': len(dataset.files)
                    }
                },
            ]
        }
    })
Esempio n. 9
0
def nooutput(stream):
    yield marv.set_header()
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            return
        yield marv.push(msg)
Esempio n. 10
0
def images(cam):
    """Extract images from input stream to jpg files.

    Args:
        cam: Input stream of raw rosbag messages.

    Returns:
        File instances for images of input stream.
    """
    # Set output stream title and pull first message
    yield marv.set_header(title=cam.topic)

    # Fetch and process first 20 image messages
    name_template = '%s-{}.jpg' % cam.topic.replace('/', ':')[1:]
    while True:
        idx, msg = yield marv.pull(cam, enumerate=True)
        if msg is None or idx >= 20:
            break

        # Deserialize raw ros message
        pytype = get_message_type(cam)
        rosmsg = pytype()
        rosmsg.deserialize(msg.data)

        # Write image to jpeg and push it to output stream
        img = imgmsg_to_cv2(rosmsg, "rgb8")
        name = name_template.format(idx)
        imgfile = yield marv.make_file(name)
        cv2.imwrite(imgfile.path, img)
        yield marv.push(imgfile)
Esempio n. 11
0
def image(cam):
    """Extract first image of input stream to jpg file.

    Args:
        cam: Input stream of raw rosbag messages.

    Returns:
        File instance for first image of input stream.
    """
    # Set output stream title and pull first message
    yield marv.set_header(title=cam.topic)
    msg = yield marv.pull(cam)
    if msg is None:
        return

    # Deserialize raw ros message
    pytype = get_message_type(cam)
    rosmsg = pytype()
    rosmsg.deserialize(msg.data)

    # Write image to jpeg and push it to output stream
    name = '{}.jpg'.format(cam.topic.replace('/', ':')[1:])
    imgfile = yield marv.make_file(name)
    img = imgmsg_to_cv2(rosmsg, "rgb8")
    cv2.imwrite(imgfile.path, img, (cv2.IMWRITE_JPEG_QUALITY, 60))
    yield marv.push(imgfile)
Esempio n. 12
0
def trajectory(navsatfixes):
    navsatfix = yield marv.pull(navsatfixes)  # Only one topic for now
    if not navsatfix:
        raise marv.Abort()
    yield marv.set_header(title=navsatfix.title)
    features = []
    prev_quality = None
    timestamps = []
    while True:
        msg = yield marv.pull(navsatfix)
        if msg is None:
            break

        dt = msg['timestamp']
        timestamps.append(int(dt * 1e9))

        # Whether to output an augmented fix is determined by both the fix
        # type and the last time differential corrections were received.  A
        # fix is valid when status >= STATUS_FIX.
        # STATUS_NO_FIX =  -1 -> unable to fix position       -> color id 0 = red
        # STATUS_FIX =      0 -> unaugmented fix              -> color id 1 = orange
        # STATUS_SBAS_FIX = 1 -> satellite-based augmentation -> color id 2 = blue
        # STATUS_GBAS_FIX = 2 -> ground-based augmentation    -> color id 3 = green
        #                     -> unknown status id            -> color id 4 = black
        if -1 <= msg['status'] <= 2:
            quality = msg['status'] + 1
        else:
            quality = 4
        if quality != prev_quality:
            color = (
                (1., 0., 0., 1.),  # rgba
                (1., 0.65, 0., 1.),
                (0., 0., 1., 1.),
                (0., 1., 0., 1.))[quality]
            coords = []
            feat = {
                'properties': {
                    'color': color,
                    'width': 4.,
                    'timestamps': timestamps,
                    'markervertices':
                    [c * 30 for c in (0., 0., -1., .3, -1., -.3)]
                },
                'geometry': {
                    'line_string': {
                        'coordinates': coords
                    }
                }
            }
            features.append(feat)
            prev_quality = quality
        coords.append((msg['lon'], msg['lat']))
    if features:
        out = {'feature_collection': {'features': features}}
        yield marv.push(out)
Esempio n. 13
0
def bagmeta_table(bagmeta, dataset):
    """Table widget listing metadata for each bag of dataset.

    Useful for detail_summary_widgets.
    """
    dataset, bagmeta = yield marv.pull_all(dataset, bagmeta)
    columns = [
        {
            'title': 'Name',
            'formatter': 'rellink'
        },
        {
            'title': 'Size',
            'formatter': 'filesize'
        },
        {
            'title': 'Start time',
            'formatter': 'datetime'
        },
        {
            'title': 'End time',
            'formatter': 'datetime'
        },
        {
            'title': 'Duration',
            'formatter': 'timedelta'
        },
        {
            'title': 'Message count',
            'align': 'right'
        },
    ]
    rows = [{
        'id':
        idx,
        'cells': [{
            'link': {
                'href': '{}'.format(idx),
                'title': os.path.basename(f.path)
            }
        }, {
            'uint64': f.size
        }, {
            'timestamp': bag.start_time
        }, {
            'timestamp': bag.end_time
        }, {
            'timedelta': bag.duration
        }, {
            'uint64': bag.msg_count
        }]
    } for idx, (bag, f) in enumerate(zip(bagmeta.bags, dataset.files))]
    yield marv.push({'table': {'columns': columns, 'rows': rows}})
Esempio n. 14
0
def galleries(stream):
    """Galleries for all images streams.

    Used by marv_robotics.detail.images_section.
    """
    yield marv.set_header(title=stream.title)
    images = []
    while True:
        img = yield marv.pull(stream)
        if img is None:
            break
        images.append({'src': img.relpath})
    yield marv.push({'title': stream.title, 'gallery': {'images': images}})
Esempio n. 15
0
def images_section(galleries, title):
    """Section with galleries of images for each images stream."""
    tmp = []
    while True:
        msg = yield marv.pull(galleries)
        if msg is None:
            break
        tmp.append(msg)
    galleries = tmp
    galleries = sorted(galleries, key=lambda x: x.title)
    widgets = yield marv.pull_all(*galleries)
    if widgets:
        yield marv.push({'title': title, 'widgets': widgets})
Esempio n. 16
0
def fulltext_per_topic(stream):
    yield marv.set_header()  # TODO: workaround
    words = set()
    pytype = get_message_type(stream)
    rosmsg = pytype()
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            break
        rosmsg.deserialize(msg.data)
        words.update(rosmsg.data.split())
    if not words:
        raise marv.Abort()
    yield marv.push({'words': list(words)})
Esempio n. 17
0
def filesizes(images):
    """Stat filesize of files.

    Args:
        images: stream of marv image files

    Returns:
        Stream of filesizes
    """
    # Pull each image and push its filesize
    while True:
        img = yield marv.pull(images)
        if img is None:
            break
        yield marv.push(img.size)
Esempio n. 18
0
def fulltext(streams):
    """Extract all text from bag file and store for fulltext search"""
    tmp = []
    while True:
        stream = yield marv.pull(streams)
        if stream is None:
            break
        tmp.append(stream)
    streams = tmp
    if not streams:
        raise marv.Abort()

    msgs = yield marv.pull_all(*streams)
    words = {x for msg in msgs for x in msg.words}
    yield marv.push({'words': list(words)})
Esempio n. 19
0
def trajectory(navsatfixes):
    navsatfix = yield marv.pull(navsatfixes)  # Only one topic for now
    if not navsatfix:
        raise marv.Abort()
    yield marv.set_header(title=navsatfix.title)
    features = []
    quality = None
    coords = []
    timestamps = []
    while True:
        msg = yield marv.pull(navsatfix)
        if msg is None:
            break

        dt = msg['timestamp']
        timestamps.append(int(dt * 1e9))

        # Whether to output an augmented fix is determined by both the fix
        # type and the last time differential corrections were received.  A
        # fix is valid when status >= STATUS_FIX.
        # STATUS_NO_FIX =  -1 -> unable to fix position       -> color id 0 = red
        # STATUS_FIX =      0 -> unaugmented fix              -> color id 1 = orange
        # STATUS_SBAS_FIX = 1 -> satellite-based augmentation -> color id 2 = blue
        # STATUS_GBAS_FIX = 2 -> ground-based augmentation    -> color id 3 = green
        #                     -> unknown status id            -> color id 4 = black
        if -1 <= msg['status'] <= 2:
            new_quality = msg['status'] + 1
        else:
            new_quality = 4

        # start new feature if quality changed
        if quality != new_quality:
            if coords:
                features.append(_create_feature(coords, quality, timestamps))
            quality = new_quality
            coords = []
            timestamps = []

        coords.append((msg['lon'], msg['lat']))

    if coords:
        features.append(_create_feature(coords, quality, timestamps))

    if features:
        out = {'feature_collection': {'features': features}}
        yield marv.push(out)
Esempio n. 20
0
def section_test(node_test):
    value = yield marv.pull(node_test)
    value = value.value
    yield marv.push({
        'title':
        'Test',
        'widgets': [{
            'keyval': {
                'items': [{
                    'title': 'value',
                    'cell': {
                        'uint64': value
                    }
                }]
            }
        }]
    })
Esempio n. 21
0
def summary_keyval(dataset, bagmeta):
    """Keyval widget summarizing bag metadata.

    Useful for detail_summary_widgets.
    """
    dataset, bagmeta = yield marv.pull_all(dataset, bagmeta)
    yield marv.push({
        'keyval': {
            'items': [{
                'title': 'size',
                'formatter': 'filesize',
                'list': False,
                'cell': {
                    'uint64': sum(x.size for x in dataset.files)
                }
            }, {
                'title': 'files',
                'list': False,
                'cell': {
                    'uint64': len(dataset.files)
                }
            }, {
                'title': 'start time',
                'formatter': 'datetime',
                'list': False,
                'cell': {
                    'timestamp': bagmeta.start_time
                }
            }, {
                'title': 'end time',
                'formatter': 'datetime',
                'list': False,
                'cell': {
                    'timestamp': bagmeta.end_time
                }
            }, {
                'title': 'duration',
                'formatter': 'timedelta',
                'list': False,
                'cell': {
                    'timedelta': bagmeta.duration
                }
            }]
        }
    })
Esempio n. 22
0
def video_section(videos, title):
    """Section displaying one video player per image stream."""
    tmps = []
    while True:
        tmp = yield marv.pull(videos)
        if tmp is None:
            break
        tmps.append(tmp)
    videos = sorted(tmps, key=lambda x: x.title)
    if not videos:
        raise marv.Abort()

    videofiles = yield marv.pull_all(*videos)
    widgets = [{'title': video.title, 'video': {'src': videofile.relpath}}
               for video, videofile in zip(videos, videofiles)]
    assert len(set(x['title'] for x in widgets)) == len(widgets)
    if widgets:
        yield marv.push({'title': title, 'widgets': widgets})
Esempio n. 23
0
def positions(stream):
    yield marv.set_header(title=stream.topic)
    pytype = get_message_type(stream)
    rosmsg = pytype()
    erroneous = 0
    e_offset = None
    n_offset = None
    u_offset = None
    positions = []
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            break
        rosmsg.deserialize(msg.data)
        if not hasattr(rosmsg, 'status') or \
           np.isnan(rosmsg.longitude) or \
           np.isnan(rosmsg.latitude) or \
           np.isnan(rosmsg.altitude) or \
           np.isnan(rosmsg.position_covariance[0]):
            erroneous += 1
            continue

        e, n, _, _ = utm.from_latlon(rosmsg.latitude, rosmsg.longitude)
        if e_offset is None:
            e_offset = e
            n_offset = n
            u_offset = rosmsg.altitude
        e = e - e_offset
        n = n - n_offset
        u = rosmsg.altitude - u_offset

        # TODO: why do we accumulate?
        positions.append([rosmsg.header.stamp.to_sec(),
                          rosmsg.latitude,
                          rosmsg.longitude,
                          rosmsg.altitude,
                          e, n, u,
                          rosmsg.status.status,
                          np.sqrt(rosmsg.position_covariance[0])])
    if erroneous:
        log = yield marv.get_logger()
        log.warn('skipped %d erroneous messages', erroneous)
    if positions:
        yield marv.push({'values': positions})
Esempio n. 24
0
def image_section(image, title):
    """Create detail section with one image.

    Args:
        title (str): Title to be displayed for detail section.
        image: marv image file.

    Returns
        One detail section.
    """
    # pull first image
    img = yield marv.pull(image)
    if img is None:
        return

    # create image widget and section containing it
    widget = {'title': image.title, 'image': {'src': img.relpath}}
    section = {'title': title, 'widgets': [widget]}
    yield marv.push(section)
Esempio n. 25
0
def combined_section(title, images, filesizes, filesize_plot):
    # A gallery of images
    imgs = []
    gallery = {'title': images.title, 'gallery': {'images': imgs}}

    # A table with two columns
    rows = []
    columns = [{
        'title': 'Name',
        'formatter': 'rellink'
    }, {
        'title': 'Size',
        'formatter': 'filesize'
    }]
    table = {'table': {'columns': columns, 'rows': rows}}

    # pull images and filesizes synchronously
    while True:
        img, filesize = yield marv.pull_all(images, filesizes)
        if img is None:
            break
        imgs.append({'src': img.relpath})
        rows.append({
            'cells': [
                {
                    'link': {
                        'href': img.relpath,
                        'title': os.path.basename(img.relpath)
                    }
                },
                {
                    'uint64': filesize
                },
            ]
        })

    # pull filesize_plot AFTER individual messages
    plot = yield marv.pull(filesize_plot)

    # section containing multiple widgets
    section = {'title': title, 'widgets': [table, plot, gallery]}
    yield marv.push(section)
Esempio n. 26
0
def gnss_section(plots, title):
    """Section displaying GNSS plots."""
    # tmps = []
    # tmp = yield marv.pull(plots)
    # while tmp:
    #     tmps.append(tmp)
    #     tmp = yield marv.pull(plots)
    # plots = tmps
    # TODO: no foreaching right now
    plots = [plots]

    widgets = []
    for plot in plots:
        plotfile = yield marv.pull(plot)
        if plotfile:
            widgets.append({'title': plot.title,
                            'image': {'src': plotfile.relpath}})
    assert len(set(x['title'] for x in widgets)) == len(widgets)
    if widgets:
        yield marv.push({'title': title, 'widgets': widgets})
Esempio n. 27
0
def imus(stream):
    yield marv.set_header(title=stream.topic)
    pytype = get_message_type(stream)
    rosmsg = pytype()
    erroneous = 0
    imus = []
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            break
        rosmsg.deserialize(msg.data)
        if np.isnan(rosmsg.orientation.x):
            erroneous += 1
            continue

        # TODO: why do we accumulate?
        imus.append([rosmsg.header.stamp.to_sec(), yaw_angle(rosmsg.orientation)])
    if erroneous:
        log = yield marv.get_logger()
        log.warn('skipped %d erroneous messages', erroneous)
    yield marv.push({'values': imus})
Esempio n. 28
0
def navsatorients(stream):
    log = yield marv.get_logger()
    yield marv.set_header(title=stream.topic)
    pytype = get_message_type(stream)
    rosmsg = pytype()
    erroneous = 0
    navsatorients = []
    while True:
        msg = yield marv.pull(stream)
        if msg is None:
            break

        rosmsg.deserialize(msg.data)
        if np.isnan(rosmsg.yaw):
            erroneous += 1
            continue

        # TODO: why do we accumulate?
        navsatorients.append([rosmsg.header.stamp.to_sec(), rosmsg.yaw])
    if erroneous:
        log.warn('skipped %d erroneous messages', erroneous)
    yield marv.push({'values': navsatorients})
Esempio n. 29
0
def gallery_section(images, title):
    """Create detail section with gallery.

    Args:
        title (str): Title to be displayed for detail section.
        images: stream of marv image files

    Returns
        One detail section.
    """
    # pull all images
    imgs = []
    while True:
        img = yield marv.pull(images)
        if img is None:
            break
        imgs.append({'src': img.relpath})
    if not imgs:
        return

    # create gallery widget and section containing it
    widget = {'title': images.title, 'gallery': {'images': imgs}}
    section = {'title': title, 'widgets': [widget]}
    yield marv.push(section)
Esempio n. 30
0
def trajectory_section(geojson, title, minzoom, maxzoom, tile_server_protocol):
    """Section displaying trajectory on a map.

    Args:
        tile_server_protocol (str): Set to ``https:`` if you host marv
            behind http and prefer the tile requests to be secured.
    """
    geojson = yield marv.pull(geojson)
    if not geojson:
        raise marv.Abort()
    layers = [
        {'title': 'Background',
         'tiles': [
             {'title': 'Roadmap',
              'url': '%s//[abc].osm.ternaris.com/styles/osm-bright/rendered/{z}/{x}/{y}.png' % tile_server_protocol,
              'attribution': '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
              'retina': 3,
              'zoom': {'min': 0, 'max': 20}},
             {'title': 'Satellite',
              'url': '%s//server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png' % tile_server_protocol,
              'attribution': 'Sources: Esri, DigitalGlobe, GeoEye, Earthstar Geographics, CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS User Community',
              'zoom': {'min': 0, 'max': 18}},
         ]},
        {'title': 'Trajectory',
         'color': (0., 1., 0., 1.),
         'geojson': geojson},
    ]
    dct = make_map_dict({
        'layers': layers,
        'zoom': {'min': minzoom, 'max': maxzoom},
    })
    jsonfile = yield marv.make_file('data.json')
    with open(jsonfile.path, 'w') as f:
        json.dump(dct, f, sort_keys=True)
    yield marv.push({'title': title,
                     'widgets': [{'map_partial': 'marv-partial:{}'.format(jsonfile.relpath)}]})