Renderer *renderer_scrolling_plots_new (Viewer *viewer)
{
    RendererScrollingPlots *self = 
        (RendererScrollingPlots*) calloc (1, sizeof (RendererScrollingPlots));
    self->viewer = viewer;
    self->renderer.draw = scrolling_plots_draw;
    self->renderer.destroy = scrolling_plots_free;
    self->renderer.name = (char*)"Scrolling Plots";
    self->renderer.user = self;
    self->renderer.enabled = 1;

    self->renderer.widget = gtk_alignment_new (0, 0.5, 1.0, 0);

    self->lcm = globals_get_lcm ();

    self->pw = BOT_GTK_PARAM_WIDGET (bot_gtk_param_widget_new ());
    gtk_container_add (GTK_CONTAINER (self->renderer.widget), 
            GTK_WIDGET(self->pw));
    gtk_widget_show (GTK_WIDGET (self->pw));

    bot_gtk_param_widget_add_int (self->pw, PARAM_NAME_SIZE,
            BOT_GTK_PARAM_WIDGET_SLIDER, 50, 800, 10, 150);
    bot_gtk_param_widget_add_double (self->pw, PARAM_NAME_GRAPH_TIMESPAN, 
            BOT_GTK_PARAM_WIDGET_SLIDER, 1, 20, 0.5, 5);
    bot_gtk_param_widget_add_booleans (self->pw, 
            BOT_GTK_PARAM_WIDGET_TOGGLE_BUTTON, PARAM_NAME_FREEZE, 0, NULL);
    bot_gtk_param_widget_add_booleans (self->pw, (BotGtkParamWidgetUIHint) 0,
                                       PARAM_NAME_RENDER_PSI_DISTANCE, 1, NULL);
    bot_gtk_param_widget_add_booleans (self->pw, (BotGtkParamWidgetUIHint)0, 
            PARAM_NAME_SHOW_LEGEND, 0, NULL);

    g_signal_connect (G_OBJECT (self->pw), "changed", 
            G_CALLBACK (on_param_widget_changed), self);

    
    // psi_distance plot
    self->psi_distance_plot = bot_gl_scrollplot2d_new ();
    bot_gl_scrollplot2d_set_title        (self->psi_distance_plot, "Psi distance");
    bot_gl_scrollplot2d_set_text_color   (self->psi_distance_plot, 0.7, 0.7, 0.7, 1);
    bot_gl_scrollplot2d_set_bgcolor      (self->psi_distance_plot, 0.1, 0.1, 0.1, 0.7);
    bot_gl_scrollplot2d_set_border_color (self->psi_distance_plot, 1, 1, 1, 0.7);
    bot_gl_scrollplot2d_set_ylim    (self->psi_distance_plot, 0.2, 1);
    bot_gl_scrollplot2d_add_plot    (self->psi_distance_plot, "control", 1000);
    bot_gl_scrollplot2d_set_color   (self->psi_distance_plot, "control", 0, 0, 1, 1);
    bot_gl_scrollplot2d_add_plot    (self->psi_distance_plot, "status", 1000);
    bot_gl_scrollplot2d_set_color   (self->psi_distance_plot, "status", 1, 0, 0, 1);

    // legends?
    BotGlScrollPlot2dLegendLocation legloc = BOT_GL_SCROLLPLOT2D_HIDDEN;
    if (bot_gtk_param_widget_get_bool (self->pw, PARAM_NAME_SHOW_LEGEND)) {
        legloc = BOT_GL_SCROLLPLOT2D_TOP_RIGHT;
    }
    bot_gl_scrollplot2d_set_show_legend (self->psi_distance_plot, legloc);

    // subscribe to LCM messages
    navlcm_class_param_t_subscribe (self->lcm, "CLASS_STATE", on_class_state, self);

    return &self->renderer;
}
Example #2
0
static BotRenderer* renderer_laser_new(BotViewer *viewer, lcm_t * lcm, BotParam * param, BotFrames * frames)
{
  RendererLaser *self = (RendererLaser*) calloc(1, sizeof(RendererLaser));
  g_assert(self);

  self->viewer = viewer;

  BotRenderer *renderer = &self->renderer;
  renderer->draw = renderer_laser_draw;
  renderer->destroy = renderer_laser_destroy;
  renderer->user = self;
  renderer->name = RENDERER_NAME;
  renderer->enabled = 1;

  self->lcm = lcm;
  self->bot_param = param;
  self->bot_frames = frames;

  if (!self->lcm) {
    ERR("Error: setup_renderer_laser() failed no LCM provided "
    "object\n");
    renderer_laser_destroy(renderer);
    return NULL;
  }

  self->param_scan_memory = 50;
  self->param_color_mode = COLOR_MODE_LASER;
  self->param_max_buffer_size = MAX_SCAN_MEMORY;
  self->param_z_buffer = TRUE;
  self->param_big_points = FALSE;
  self->param_spacial_decimate = FALSE;
  self->param_color_mode_z_max_z = COLOR_MODE_Z_MAX_Z;
  self->param_color_mode_z_min_z = COLOR_MODE_Z_MIN_Z;
  self->param_max_draw_z = COLOR_MODE_Z_MAX_Z;
  self->param_min_draw_z = COLOR_MODE_Z_MIN_Z;
  self->param_max_draw_range = MAX_DRAW_RANGE;
  self->param_alpha = 1;
  self->param_max_buffer_size = MAX_SCAN_MEMORY; 

  if (viewer) {
    /* setup parameter widget */
    self->pw = BOT_GTK_PARAM_WIDGET(bot_gtk_param_widget_new());
    renderer->widget = gtk_vbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(renderer->widget), GTK_WIDGET(self->pw), TRUE, TRUE, 0);
    bot_gtk_param_widget_add_int(self->pw, PARAM_SCAN_MEMORY, BOT_GTK_PARAM_WIDGET_SPINBOX, 1, MAX_SCAN_MEMORY, 1,
        self->param_scan_memory);
    bot_gtk_param_widget_add_enum(self->pw, PARAM_COLOR_MODE, BOT_GTK_PARAM_WIDGET_MENU, self->param_color_mode,
        "Laser", COLOR_MODE_LASER, "Drab", COLOR_MODE_DRAB, "Intensity", COLOR_MODE_INTENSITY, "Height", COLOR_MODE_Z, "Workspace", COLOR_MODE_WORKSPACE,
        NULL);
    bot_gtk_param_widget_add_booleans(self->pw, 0, PARAM_Z_BUFFER, self->param_z_buffer, NULL);
    bot_gtk_param_widget_add_booleans(self->pw, 0, PARAM_BIG_POINTS, self->param_big_points, NULL);
    bot_gtk_param_widget_add_booleans(self->pw, 0, PARAM_SPATIAL_DECIMATE, self->param_spacial_decimate, NULL);
    bot_gtk_param_widget_add_booleans(self->pw, 0, PARAM_Z_RELATIVE, 0, NULL);

    bot_gtk_param_widget_add_double(self->pw, PARAM_ALPHA, BOT_GTK_PARAM_WIDGET_SLIDER,
        0, 1, .01, self->param_alpha);

    bot_gtk_param_widget_add_double(self->pw, PARAM_COLOR_MODE_Z_MAX_Z, BOT_GTK_PARAM_WIDGET_SPINBOX,
        COLOR_MODE_Z_MIN_Z, COLOR_MODE_Z_MAX_Z, COLOR_MODE_Z_DZ, self->param_color_mode_z_max_z);
    bot_gtk_param_widget_add_double(self->pw, PARAM_COLOR_MODE_Z_MIN_Z, BOT_GTK_PARAM_WIDGET_SPINBOX,
        COLOR_MODE_Z_MIN_Z, COLOR_MODE_Z_MAX_Z, COLOR_MODE_Z_DZ, self->param_color_mode_z_min_z);
    bot_gtk_param_widget_add_double(self->pw, PARAM_MIN_DRAW_Z, BOT_GTK_PARAM_WIDGET_SPINBOX, COLOR_MODE_Z_MIN_Z,
        COLOR_MODE_Z_MAX_Z, COLOR_MODE_Z_DZ, self->param_min_draw_z);
    bot_gtk_param_widget_add_double(self->pw, PARAM_MAX_DRAW_Z, BOT_GTK_PARAM_WIDGET_SPINBOX, COLOR_MODE_Z_MIN_Z,
        COLOR_MODE_Z_MAX_Z, COLOR_MODE_Z_DZ, self->param_max_draw_z);
    bot_gtk_param_widget_add_double(self->pw, PARAM_MAX_DRAW_RANGE, BOT_GTK_PARAM_WIDGET_SPINBOX, 0,
        MAX_DRAW_RANGE, 0.1, MAX_DRAW_RANGE); // from short to sick range

    bot_gtk_param_widget_add_int(self->pw, PARAM_MAX_BUFFER_SIZE, BOT_GTK_PARAM_WIDGET_SPINBOX, 1, MAX_SCAN_MEMORY, 1,
        self->param_max_buffer_size);

    GtkWidget *clear_button = gtk_button_new_with_label("Clear memory");
    gtk_box_pack_start(GTK_BOX(renderer->widget), clear_button, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(clear_button), "clicked", G_CALLBACK(on_clear_button), self);
    GtkWidget *save_button = gtk_button_new_with_label("Save To Points File");
    gtk_box_pack_start(GTK_BOX(renderer->widget), save_button, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(save_button), "clicked", G_CALLBACK(on_save_button), self);
    gtk_widget_show_all(renderer->widget);

    /* setup signal callbacks */
    g_signal_connect(G_OBJECT(self->pw), "changed", G_CALLBACK(on_param_widget_changed), self);
    g_signal_connect(G_OBJECT(viewer), "load-preferences", G_CALLBACK(on_load_preferences), self);
    g_signal_connect(G_OBJECT(viewer), "save-preferences", G_CALLBACK(on_save_preferences), self);
  }

  // iterate through planar lidars, subscribing to thier LCM and
  // initializing the channels' hash table and array
  self->channels_hash = g_hash_table_new(g_str_hash, g_str_equal);
  self->channels = g_ptr_array_new();
  bot_core_planar_lidar_t_subscription_t *hid;

  char **planar_lidar_names = bot_param_get_all_planar_lidar_names(self->bot_param);
  if (planar_lidar_names) {
    for (int pind = 0; planar_lidar_names[pind] != NULL; pind++) {
      char conf_path[1024];
      bot_param_get_planar_lidar_prefix(self->bot_param, planar_lidar_names[pind], conf_path, sizeof(conf_path));
      char channel_path[1024];
      sprintf(channel_path, "%s.lcm_channel", conf_path);
      char * channel_name;
      int ret = bot_param_get_str(self->bot_param, channel_path, &channel_name);
      if (ret < 0) {
        printf("No LCM Channel for lidar %s\n", planar_lidar_names[pind]);
        continue;
      }
      printf("subscribing to channel %s for laser %s\n", channel_name, planar_lidar_names[pind]);
      hid = bot_core_planar_lidar_t_subscribe(self->lcm, channel_name, on_laser, self);
      self->lcm_hids = g_list_append(self->lcm_hids, hid);
      free(channel_name);
    }
    g_strfreev(planar_lidar_names);
  }
  else {
    fprintf(stderr, "["__FILE__":%d] Error: Could not"
    " get lidar names.\n", __LINE__);
  }

  return &self->renderer;
}
Example #3
0
void 
setup_gfe_renderer(BotViewer *viewer, int render_priority, const char *wavefront_fname0, const char *wavefront_fname1)
{

    GfeRenderer *self = (GfeRenderer*) calloc (1, sizeof (GfeRenderer));

    BotRenderer *renderer = &self->renderer;

    renderer->draw = _renderer_draw;
    renderer->destroy = _renderer_free;

    renderer->widget = bot_gtk_param_widget_new();
    renderer->name = RENDERER_NAME;
    renderer->user = self;
    renderer->enabled = 1;

    self->viewer = viewer;

    self->pw = BOT_GTK_PARAM_WIDGET(renderer->widget);

    double default_scale = 1.0;
    double default_rot_x  = 0;
    double default_rot_y = 0;
    double default_rot_z   = 0;
    double default_dx    = 0;
    double default_dy    = 0;
    double default_dz    = 0;

    printf("%s is fname0\n", wavefront_fname0);
    printf("%s is fname1\n", wavefront_fname1);

    if(wavefront_fname0) {
        self->wavefront_model = bot_wavefront_model_create(wavefront_fname0);      
	double minv[3];
        double maxv[3];
        bot_wavefront_model_get_extrema(self->wavefront_model, minv, maxv);

        double span_x = maxv[0] - minv[0];
        double span_y = maxv[1] - minv[1];
        double span_z = maxv[2] - minv[2];

        double span_max = MAX(span_x, MAX(span_y, span_z));

        // leave the default scale and translations at default
        default_scale = 1.0;
        default_dx = 0.0;
        default_dy = 0.0;
        default_dz = 0.0;

        printf("WAVEFRONT extrema: [%f, %f, %f] [%f, %f, %f]\n", 
                minv[0], minv[1], minv[2],
                maxv[0], maxv[1], maxv[2]);
        printf("WAVEFRONT initial scale: %f\n", default_scale);
        printf("WAVEFRONT initial offsets: [%f, %f, %f]\n", default_dx, default_dy, default_dz);
    }



    if(wavefront_fname1) {
        self->wavefront_model2 = bot_wavefront_model_create(wavefront_fname1);      
	double minv[3];
        double maxv[3];
        bot_wavefront_model_get_extrema(self->wavefront_model, minv, maxv);

        double span_x = maxv[0] - minv[0];
        double span_y = maxv[1] - minv[1];
        double span_z = maxv[2] - minv[2];

        double span_max = MAX(span_x, MAX(span_y, span_z));

        // leave the default scale and translations at default
        default_scale = 1.0;
        default_dx = 2.0;
        default_dy = 0.0;
        default_dz = 0.0;

        printf("WAVEFRONT extrema: [%f, %f, %f] [%f, %f, %f]\n", 
                minv[0], minv[1], minv[2],
                maxv[0], maxv[1], maxv[2]);
        printf("WAVEFRONT initial scale: %f\n", default_scale);
        printf("WAVEFRONT initial offsets: [%f, %f, %f]\n", default_dx, default_dy, default_dz);
    }




    bot_gtk_param_widget_add_double(self->pw, PARAM_SCALE, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, 0, 99999999999, 0.00000001, default_scale);

    bot_gtk_param_widget_add_double(self->pw, PARAM_DX, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -9999999999, 99999999999, 0.01, default_dx);
    bot_gtk_param_widget_add_double(self->pw, PARAM_DY, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -9999999999, 99999999999, 0.01, default_dy);
    bot_gtk_param_widget_add_double(self->pw, PARAM_DZ, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -9999999999, 99999999999, 0.01, default_dz);

    bot_gtk_param_widget_add_double(self->pw, PARAM_ROT_X, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -180, 180, 0.1, default_rot_x);
    bot_gtk_param_widget_add_double(self->pw, PARAM_ROT_Y, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -180, 180, 0.1, default_rot_y);
    bot_gtk_param_widget_add_double(self->pw, PARAM_ROT_Z, 
            BOT_GTK_PARAM_WIDGET_SPINBOX, -180, 180, 0.1, default_rot_z);

    gtk_widget_show_all(renderer->widget);

    g_signal_connect (G_OBJECT (self->pw), "changed", 
                      G_CALLBACK (on_param_widget_changed), self);

    bot_viewer_add_renderer(viewer, &self->renderer, render_priority);
}
void bot_frames_add_frame_modifier_to_viewer(BotViewer *viewer, int render_priority, BotFrames * frames)
{

  RendererFrames *self = (RendererFrames*) calloc(1, sizeof(RendererFrames));

  BotRenderer *renderer = &self->renderer;

  renderer->draw = draw;
  renderer->destroy = destroy_renderer_frames;

  renderer->widget = gtk_vbox_new(FALSE, 0);
  renderer->name = strdup(RENDERER_NAME);
  renderer->user = self;
  renderer->enabled = 1;

  BotEventHandler *ehandler = &self->ehandler;
  ehandler->name = renderer->name;
  ehandler->enabled = 1;
  ehandler->pick_query = NULL;
  ehandler->key_press = NULL;
  ehandler->hover_query = NULL;
  ehandler->mouse_press = NULL;
  ehandler->mouse_release = NULL;
  ehandler->mouse_motion = NULL;
  ehandler->user = self;

  self->viewer = viewer;
  self->frames = frames;
  bot_frames_add_update_subscriber(self->frames, frames_update_handler, (void *) self);

  self->pw = BOT_GTK_PARAM_WIDGET(bot_gtk_param_widget_new());

  self->rootFrame = bot_frames_get_root_name(self->frames);
  int num_frames = bot_frames_get_num_frames(self->frames);

  char ** frame_names = bot_frames_get_frame_names(self->frames);

  self->numFrames = num_frames + 1; //need space for extra "empty" one
  self->frameNames = calloc(self->numFrames, sizeof(char *));
  self->frameNums = calloc(self->numFrames, sizeof(int));
  self->frameNums[0] = 0;
  self->frameNames[0] = "";
  for (int i = 1; i < self->numFrames; i++) {
    self->frameNums[i] = i;
    self->frameNames[i] = strdup(frame_names[i - 1]);
  }
  g_strfreev(frame_names);
  bot_gtk_param_widget_add_enumv(self->pw, PARAM_FRAME_SELECT, BOT_GTK_PARAM_WIDGET_DEFAULTS, 0, self->numFrames,
      (const char **) self->frameNames, self->frameNums);

  gtk_box_pack_start(GTK_BOX(renderer->widget), GTK_WIDGET(self->pw), TRUE, TRUE, 0);

  bot_gtk_param_widget_add_double(self->pw, PARAM_X, BOT_GTK_PARAM_WIDGET_SPINBOX, -1000, 1000, 0.001, 0);
  bot_gtk_param_widget_add_double(self->pw, PARAM_Y, BOT_GTK_PARAM_WIDGET_SPINBOX, -1000, 1000, 0.001, 0);
  bot_gtk_param_widget_add_double(self->pw, PARAM_Z, BOT_GTK_PARAM_WIDGET_SPINBOX, -1000, 1000, 0.001, 0);
  bot_gtk_param_widget_add_double(self->pw, PARAM_ROLL, BOT_GTK_PARAM_WIDGET_SPINBOX, -181, 181, 0.1, 0);
  bot_gtk_param_widget_add_double(self->pw, PARAM_PITCH, BOT_GTK_PARAM_WIDGET_SPINBOX, -181, 181, 0.1, 0);
  bot_gtk_param_widget_add_double(self->pw, PARAM_YAW, BOT_GTK_PARAM_WIDGET_SPINBOX, -181, 181, 0.1, 0);

  bot_gtk_param_widget_add_separator(self->pw, "");
  bot_gtk_param_widget_add_buttons(self->pw, PARAM_SAVE, NULL);

  bot_gtk_param_widget_set_enabled(self->pw, PARAM_X, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_Y, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_Z, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_ROLL, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_PITCH, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_YAW, 0);
  bot_gtk_param_widget_set_enabled(self->pw, PARAM_SAVE, 0);

  gtk_widget_show_all(renderer->widget);

  g_signal_connect(G_OBJECT(self->pw), "changed", G_CALLBACK(on_param_widget_changed), self);
  on_param_widget_changed(self->pw, "", self);

  bot_viewer_add_renderer(viewer, &self->renderer, render_priority);
}
Renderer *renderer_scrolling_plots_new (Viewer *viewer)
{
    RendererScrollingPlots *self = 
        (RendererScrollingPlots*) calloc (1, sizeof (RendererScrollingPlots));
    self->viewer = viewer;
    self->renderer.draw = scrolling_plots_draw;
    self->renderer.destroy = scrolling_plots_free;
    self->renderer.name = "Scrolling Plots";
    self->renderer.user = self;
    self->renderer.enabled = 1;

    self->renderer.widget = gtk_alignment_new (0, 0.5, 1.0, 0);
    self->atrans = globals_get_atrans();

    self->lcm = globals_get_lcm ();

    self->pw = BOT_GTK_PARAM_WIDGET (bot_gtk_param_widget_new ());
    gtk_container_add (GTK_CONTAINER (self->renderer.widget), 
            GTK_WIDGET(self->pw));
    gtk_widget_show (GTK_WIDGET (self->pw));

    bot_gtk_param_widget_add_int (self->pw, PARAM_NAME_SIZE,
            BOT_GTK_PARAM_WIDGET_SLIDER, 50, 800, 10, 150);
    bot_gtk_param_widget_add_double (self->pw, PARAM_NAME_GRAPH_TIMESPAN, 
            BOT_GTK_PARAM_WIDGET_SLIDER, 1, 20, 0.5, 5);
    bot_gtk_param_widget_add_booleans (self->pw, 
            BOT_GTK_PARAM_WIDGET_TOGGLE_BUTTON, PARAM_NAME_FREEZE, 0, NULL);
    bot_gtk_param_widget_add_booleans (self->pw, 0,
                                       PARAM_NAME_RENDER_NAVIGATOR_ROTATION, 1, 
                                       PARAM_NAME_RENDER_NAVIGATOR_TRANSLATION, 1, 
                                       NULL);
    bot_gtk_param_widget_add_booleans (self->pw, 0,
                                       PARAM_NAME_RENDER_ENCODER_LEFT, 1,
                                       PARAM_NAME_RENDER_ENCODER_RIGHT, 1, NULL);
    bot_gtk_param_widget_add_booleans (self->pw, 0, 
            PARAM_NAME_SHOW_LEGEND, 0, NULL);

    g_signal_connect (G_OBJECT (self->pw), "changed", 
            G_CALLBACK (on_param_widget_changed), self);

    
    BotConf *config = globals_get_config ();
    self->encoder_left_scale = 1.0;//bot_conf_get_double_or_fail (config, "calibration.encoders.WHEEL_LEFT.scale");
    self->encoder_right_scale = 1.0;//bot_conf_get_double_or_fail (config, "calibration.encoders.WHEEL_RIGHT.scale");
    globals_release_config (config);

    self->encoder_left_last = 0;
    self->encoder_right_last = 0;

    // navigator rotation
    self->navigator_rotation_plot = bot_gl_scrollplot2d_new ();
    bot_gl_scrollplot2d_set_title        (self->navigator_rotation_plot, "Nav. Rot. Speed");
    bot_gl_scrollplot2d_set_text_color   (self->navigator_rotation_plot, 0.7, 0.7, 0.7, 1);
    bot_gl_scrollplot2d_set_bgcolor      (self->navigator_rotation_plot, 0.1, 0.1, 0.1, 0.7);
    bot_gl_scrollplot2d_set_border_color (self->navigator_rotation_plot, 1, 1, 1, 0.7);
    bot_gl_scrollplot2d_set_ylim    (self->navigator_rotation_plot, -.5, .5);
    bot_gl_scrollplot2d_add_plot    (self->navigator_rotation_plot, "control", 1000);
    bot_gl_scrollplot2d_set_color   (self->navigator_rotation_plot, "control", 0.7, 0, 0.7, 1);

    bot_gl_scrollplot2d_add_plot    (self->navigator_rotation_plot, "status", 1000);
    bot_gl_scrollplot2d_set_color   (self->navigator_rotation_plot, "status", 0, 0, 1, 1);

    //bot_gl_scrollplot2d_add_plot    (self->navigator_rotation_plot, "2500", 1000);
    //bot_gl_scrollplot2d_set_color   (self->navigator_rotation_plot, "2500", 0.8, 0.8, 0.8, 0.5);


    self->navigator_translation_plot = bot_gl_scrollplot2d_new ();
    bot_gl_scrollplot2d_set_title        (self->navigator_translation_plot, "Nav. Trans. Speed");
    bot_gl_scrollplot2d_set_text_color   (self->navigator_translation_plot, 0.7, 0.7, 0.7, 1);
    bot_gl_scrollplot2d_set_bgcolor      (self->navigator_translation_plot, 0.1, 0.1, 0.1, 0.7);
    bot_gl_scrollplot2d_set_border_color (self->navigator_translation_plot, 1, 1, 1, 0.7);
    bot_gl_scrollplot2d_set_ylim    (self->navigator_translation_plot, 0, 2.0);
    bot_gl_scrollplot2d_add_plot    (self->navigator_translation_plot, "control", 1000);
    bot_gl_scrollplot2d_set_color   (self->navigator_translation_plot, "control", 0.7, 0, 0.7, 1);

    bot_gl_scrollplot2d_add_plot    (self->navigator_translation_plot, "status", 1000);
    bot_gl_scrollplot2d_set_color   (self->navigator_translation_plot, "status", 0, 0, 1, 1);

    // left wheel encoder plot
    self->encoder_left_plot = bot_gl_scrollplot2d_new ();
    bot_gl_scrollplot2d_set_title        (self->encoder_left_plot, "Left Encoder");
    bot_gl_scrollplot2d_set_text_color   (self->encoder_left_plot, 0.7, 0.7, 0.7, 1);
    bot_gl_scrollplot2d_set_border_color (self->encoder_left_plot, 1, 1, 1, 0.7);
    bot_gl_scrollplot2d_set_bgcolor (self->encoder_left_plot, 0.1, 0.1, 0.1, 0.7);
    bot_gl_scrollplot2d_set_ylim    (self->encoder_left_plot, 0, 2.0);

    bot_gl_scrollplot2d_add_plot    (self->encoder_left_plot, "actual", 1000);
    bot_gl_scrollplot2d_set_color   (self->encoder_left_plot, "actual", 0.7, 0, 0.7, 1);

    bot_gl_scrollplot2d_add_plot    (self->encoder_left_plot, "0", 1000);
    bot_gl_scrollplot2d_set_color   (self->encoder_left_plot, "0", 0.8, 0.8, 0.8, 0.5);

    // right wheel encoder plot
    self->encoder_right_plot = bot_gl_scrollplot2d_new ();
    bot_gl_scrollplot2d_set_title        (self->encoder_right_plot, "Right Encoder");
    bot_gl_scrollplot2d_set_text_color   (self->encoder_right_plot, 0.7, 0.7, 0.7, 1);
    bot_gl_scrollplot2d_set_border_color (self->encoder_right_plot, 1, 1, 1, 0.7);
    bot_gl_scrollplot2d_set_bgcolor (self->encoder_right_plot, 0.1, 0.1, 0.1, 0.7);
    bot_gl_scrollplot2d_set_ylim    (self->encoder_right_plot, 0, 2.0);

    bot_gl_scrollplot2d_add_plot    (self->encoder_right_plot, "actual", 1000);
    bot_gl_scrollplot2d_set_color   (self->encoder_right_plot, "actual", 0.7, 0, 0.7, 1);

    bot_gl_scrollplot2d_add_plot    (self->encoder_right_plot, "0", 1000);
    bot_gl_scrollplot2d_set_color   (self->encoder_right_plot, "0", 0.8, 0.8, 0.8, 0.5);

    // legends?
    BotGlScrollPlot2dLegendLocation legloc = BOT_GL_SCROLLPLOT2D_HIDDEN;
    if (bot_gtk_param_widget_get_bool (self->pw, PARAM_NAME_SHOW_LEGEND)) {
        legloc = BOT_GL_SCROLLPLOT2D_TOP_RIGHT;
    }
    bot_gl_scrollplot2d_set_show_legend (self->navigator_rotation_plot, legloc);
    bot_gl_scrollplot2d_set_show_legend (self->navigator_translation_plot, legloc);

    // subscribe to LC messages
    fblcm_motion_cmd_t_subscribe (self->lcm, "MOTION_CMD", on_motion_cmd, self);
    
    //arlcm_encoder_t_subscribe (self->lcm, "WHEEL_LEFT", on_encoders, self);
    //arlcm_encoder_t_subscribe (self->lcm, "WHEEL_RIGHT", on_encoders, self);

    // periodically pull pose data from ATrans
    //g_timeout_add (30, get_speed_update, self);

    return &self->renderer;
}