changeset 224:5e91f5877f1f main

Latest simulator changes.
author Bob Cook <bob@bobcookdev.com>
date Thu, 17 Apr 2014 22:03:28 -0700
parents 5f11f6622bc4
children c4009187a522
files main/robots/odr-sim/ImuStatus.cpp main/robots/odr-sim/ImuStatus.h main/robots/odr-sim/Receiver.cpp main/robots/odr-sim/SimDisplay.cpp main/robots/odr-sim/SimDisplay.h main/robots/odr-sim/SonarFrontStatus.cpp main/robots/odr-sim/SonarFrontStatus.h main/robots/odr-sim/jamfile
diffstat 8 files changed, 490 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-sim/ImuStatus.cpp	Thu Apr 17 22:03:28 2014 -0700
@@ -0,0 +1,194 @@
+// ----------------------------------------------------------------------------------------
+//
+//  robots/odr-sim/ImuStatus.cpp
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  Thread that periodically sends the IMU details.
+//
+//  Copyright (c) 2013 Bob Cook
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#include "ImuStatus.h"
+
+#include "SimDisplay.h"
+
+#include "packages/common/can/can_helpers.h"
+#include "packages/common/can/can_messages.h"
+#include "packages/common/can/can_nodes.h"
+
+#include "packages/linux/can/CANMessage.h"
+
+// ----------------------------------------------------------------------------------------
+
+static void SendImuDataMessages()
+{
+#if 0
+    uint32_t msgid;
+
+    if ( SonarFrontStatus::isSonarFrontEnabled() )
+    {
+        msgid = can_build_message_id( can_node_odr_sonar_front,
+                                      can_node_broadcast,
+                                      can_dataid_sonar_front_state_enabled );
+    }
+    else
+    {
+        msgid = can_build_message_id( can_node_odr_sonar_front,
+                                      can_node_broadcast,
+                                      can_dataid_sonar_front_state_disabled );
+    }
+    CANMessage::QueueToSend( new CANMessage( msgid ) );
+#endif
+}
+
+// ----------------------------------------------------------------------------------------
+
+Poco::RWLock ImuStatus::sm_rwLock;
+bool         ImuStatus::sm_isEnabled = false;
+double       ImuStatus::sm_yaw       = 0.0;
+double       ImuStatus::sm_pitch     = 0.0;
+double       ImuStatus::sm_roll      = 0.0;
+
+// ----------------------------------------------------------------------------------------
+
+bool ImuStatus::isImuEnabled()
+{
+    Poco::RWLock::ScopedReadLock lock( sm_rwLock );
+    return sm_isEnabled;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::setImuEnabled()
+{
+    Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
+    sm_isEnabled = true;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::setImuDisabled()
+{
+    Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
+    sm_isEnabled = false;
+}
+
+// ----------------------------------------------------------------------------------------
+
+double ImuStatus::imuYaw()
+{
+    Poco::RWLock::ScopedReadLock lock( sm_rwLock );
+    return sm_yaw;
+}
+
+// ----------------------------------------------------------------------------------------
+
+double ImuStatus::imuPitch()
+{
+    Poco::RWLock::ScopedReadLock lock( sm_rwLock );
+    return sm_pitch;
+}
+
+// ----------------------------------------------------------------------------------------
+
+double ImuStatus::imuRoll()
+{
+    Poco::RWLock::ScopedReadLock lock( sm_rwLock );
+    return sm_roll;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::setImuYaw( double value )
+{
+    Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
+    sm_yaw = value;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::setImuPitch( double value )
+{
+    Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
+    sm_pitch = value;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::setImuRoll( double value )
+{
+    Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
+    sm_roll = value;
+}
+
+// ----------------------------------------------------------------------------------------
+
+ImuStatus::ImuStatus()
+    : Poco::Runnable(),
+      m_quitEvent( true /* auto-reset */ )
+{
+}
+
+// ----------------------------------------------------------------------------------------
+
+ImuStatus::~ImuStatus()
+{
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::timeToQuit()
+{
+    m_quitEvent.set();
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ImuStatus::run()
+{
+    for ( ;; )
+    {
+        try
+        {
+//                SendSonarFrontStatusMessage();
+
+//            if ( isSonarFrontEnabled() )
+//            {
+//                SendSonarFrontValueMessage();
+//            }
+        }
+        catch ( ... )
+        {
+            // nothing to do, but don't stop the thread
+        }
+
+        if ( m_quitEvent.tryWait( 500 ) ) // 500ms = 1/2 second
+        {
+            return;
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main/robots/odr-sim/ImuStatus.h	Thu Apr 17 22:03:28 2014 -0700
@@ -0,0 +1,77 @@
+// ----------------------------------------------------------------------------------------
+//
+//  robots/odr-sim/ImuStatus.h
+//    
+//  Bob Cook Development, Robotics Library
+//  http://www.bobcookdev.com/rl/
+// 
+//  Thread that periodically sends the IMU details.
+//
+//  Copyright (c) 2013 Bob Cook
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+//
+// ----------------------------------------------------------------------------------------
+
+#ifndef BCDRL_ROBOTS_ODRSIM_IMUSTATUS_H
+#define BCDRL_ROBOTS_ODRSIM_IMUSTATUS_H
+
+#include <Poco/Event.h>
+#include <Poco/Runnable.h>
+#include <Poco/RWLock.h>
+
+// ----------------------------------------------------------------------------------------
+
+class ImuStatus : public Poco::Runnable
+{
+    public:
+        static bool   isImuEnabled();
+        static void   setImuEnabled();
+        static void   setImuDisabled();
+        static double imuYaw();
+        static double imuPitch();
+        static double imuRoll();
+        static void   setImuYaw( double value );
+        static void   setImuPitch( double value );
+        static void   setImuRoll( double value );
+
+    public:
+        ImuStatus();
+        virtual ~ImuStatus();
+        virtual void run();
+        void timeToQuit();
+
+    private:
+        static void sendImuData();
+
+    private:
+        static Poco::RWLock sm_rwLock;
+        static bool         sm_isEnabled;
+        static double       sm_yaw;
+        static double       sm_pitch;
+        static double       sm_roll;
+
+    private:
+        Poco::Event m_quitEvent;
+};
+
+// ----------------------------------------------------------------------------------------
+#endif // #ifndef BCDRL_ROBOTS_ODRSIM_IMUSTATUS_H
+// ----------------------------------------------------------------------------------------
+
--- a/main/robots/odr-sim/Receiver.cpp	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/Receiver.cpp	Thu Apr 17 22:03:28 2014 -0700
@@ -7,7 +7,7 @@
 // 
 //  Update status from incoming CAN messages.
 //
-//  Copyright (c) 2011 Bob Cook
+//  Copyright (c) 2011-2013 Bob Cook
 //
 //  Permission is hereby granted, free of charge, to any person obtaining a copy
 //  of this software and associated documentation files (the "Software"), to deal
@@ -91,12 +91,12 @@
 
 void Receiver::recvMotorSpeed( CANMessage* msg )
 {
-    can_data_motor_speed data;
+    can_data_wheel_speed data;
     msg->msgData( reinterpret_cast< uint8_t* >( &data ), sizeof( data ) );
 
     if ( m_display )
     {
-        m_display->updateMotorSpeeds( data.motor_front, data.motor_rear );
+        m_display->updateMotorSpeeds( data.rpm_front, data.rpm_rear );
     }
 }
 
@@ -104,12 +104,12 @@
 
 void Receiver::recvServoPosition( CANMessage* msg )
 {
-    can_data_servo_position data;
+    can_data_wheel_position data;
     msg->msgData( reinterpret_cast< uint8_t* >( &data ), sizeof( data ) );
 
     if ( m_display )
     {
-        m_display->updateServoPositions( data.servo_front, data.servo_rear );
+        m_display->updateServoPositions( data.angle_front, data.angle_rear );
     }
 }
 
@@ -165,11 +165,11 @@
                     recvMgrUpdate( msg );
                     break;
 
-                case can_dataid_motor_speed:
+                case can_dataid_wheel_speed:
                     recvMotorSpeed( msg );
                     break;
 
-                case can_dataid_servo_position:
+                case can_dataid_wheel_position:
                     recvServoPosition( msg );
                     break;
 
--- a/main/robots/odr-sim/SimDisplay.cpp	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/SimDisplay.cpp	Thu Apr 17 22:03:28 2014 -0700
@@ -7,7 +7,7 @@
 //
 //  Window display for the ODR platform simulator.
 //
-//  Copyright (c) 2011 Bob Cook
+//  Copyright (c) 2011-2013 Bob Cook
 //
 //  Permission is hereby granted, free of charge, to any person obtaining a copy
 //  of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,7 @@
 #include <FL/Fl.H>
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Button.H>
+#include <FL/Fl_Dial.H>
 #include <FL/Fl_Double_Window.H>
 #include <FL/Fl_Hor_Slider.H>
 #include <FL/Fl_Light_Button.H>
@@ -48,6 +49,7 @@
 #include <Poco/Thread.h>
 
 #include "ControllerStatus.h"
+#include "ImuStatus.h"
 #include "SonarFrontStatus.h"
 
 // ----------------------------------------------------------------------------------------
@@ -130,6 +132,89 @@
 
 // ----------------------------------------------------------------------------------------
 
+static void ImuKeepAliveCB( Fl_Widget* widget, void* value )
+{
+    static ImuStatus    s_imuStatusRunnable;
+    static Poco::Thread s_imuStatusThread;
+
+    Fl_Light_Button* button = dynamic_cast< Fl_Light_Button* >( widget );
+    if ( button == 0 )
+    {
+        return; // opps, not what we thought?!
+    }
+
+    if ( button->value() == 0 )
+    {
+        // off
+        s_imuStatusRunnable.timeToQuit();
+        s_imuStatusThread.join();
+    }
+    else
+    {
+        // on
+        s_imuStatusThread.start( s_imuStatusRunnable );
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+static void ImuHeadingDialCB( Fl_Widget* widget, void* value )
+{
+    Fl_Dial* dial = dynamic_cast< Fl_Dial* >( widget );
+    if ( dial == 0 )
+    {
+        return; // opps, not what we thought?!
+    }
+
+    ImuStatus::setImuYaw( dial->value() );
+
+    SimDisplay* theDisplay = reinterpret_cast< SimDisplay* >( value );
+    if ( theDisplay )
+    {
+        theDisplay->updateImuValues();
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+static void ImuPitchSliderCB( Fl_Widget* widget, void* value )
+{
+    Fl_Slider* slider = dynamic_cast< Fl_Slider* >( widget );
+    if ( slider == 0 )
+    {
+        return; // opps, not what we thought?!
+    }
+
+    ImuStatus::setImuPitch( slider->value() );
+
+    SimDisplay* theDisplay = reinterpret_cast< SimDisplay* >( value );
+    if ( theDisplay )
+    {
+        theDisplay->updateImuValues();
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
+static void ImuRollSliderCB( Fl_Widget* widget, void* value )
+{
+    Fl_Slider* slider = dynamic_cast< Fl_Slider* >( widget );
+    if ( slider == 0 )
+    {
+        return; // opps, not what we thought?!
+    }
+
+    ImuStatus::setImuRoll( slider->value() );
+
+    SimDisplay* theDisplay = reinterpret_cast< SimDisplay* >( value );
+    if ( theDisplay )
+    {
+        theDisplay->updateImuValues();
+    }
+}
+
+// ----------------------------------------------------------------------------------------
+
 static void SonarFrontKeepAliveCB( Fl_Widget* widget, void* value )
 {
     static SonarFrontStatus s_sfsRunnable;
@@ -490,11 +575,65 @@
 
 // ----------------------------------------------------------------------------------------
 
+void SimDisplay::createImuControls()
+{
+    m_window->begin();
+
+    m_buttonImuKA = new Fl_Light_Button( 250, 150, 165, 20 );
+    if ( m_buttonImuKA )
+    {
+        m_buttonImuKA->label( "IMU Alive" );
+        m_buttonImuKA->selection_color( FL_GREEN );
+        m_buttonImuKA->callback( &ImuKeepAliveCB );
+    }
+
+    m_textImuValues = new Fl_Box( 250, 180, 165, 20 );
+    if ( m_textImuValues )
+    {
+        m_textImuValues->box( FL_THIN_DOWN_BOX );
+        m_textImuValues->align( FL_ALIGN_CENTER );
+        m_textImuValues->label( "0.0  0.0  0.0" );
+    }
+
+    m_dialImuHeading = new Fl_Dial( 250, 210, 75, 75 );
+    if ( m_dialImuHeading )
+    {
+        m_dialImuHeading->box( FL_ROUND_UP_BOX );
+        m_dialImuHeading->bounds( 0.0, 360.0 );
+        m_dialImuHeading->value( ImuStatus::imuYaw() );
+        m_dialImuHeading->callback( ImuHeadingDialCB, this );
+    }
+
+    m_sliderImuPitch = new Fl_Slider( 335, 210, 35, 60 );
+    if ( m_sliderImuPitch )
+    {
+        m_sliderImuPitch->label( "Pitch" );
+        m_sliderImuPitch->slider( FL_UP_BOX );
+        m_sliderImuPitch->bounds( 0.0, 20.0 );
+        m_sliderImuPitch->value( ImuStatus::imuPitch() );
+        m_sliderImuPitch->callback( ImuPitchSliderCB, this );
+    }
+
+    m_sliderImuRoll = new Fl_Slider( 380, 210, 35, 60 );
+    if ( m_sliderImuRoll )
+    {
+        m_sliderImuRoll->label( "Roll" );
+        m_sliderImuRoll->slider( FL_UP_BOX );
+        m_sliderImuRoll->bounds( 0.0, 20.0 );
+        m_sliderImuRoll->value( ImuStatus::imuRoll() );
+        m_sliderImuRoll->callback( ImuRollSliderCB, this );
+    }
+
+    m_window->end();
+}
+
+// ----------------------------------------------------------------------------------------
+
 void SimDisplay::createSonarFrontControls()
 {
     m_window->begin();
 
-    m_buttonSonarFrontKA = new Fl_Light_Button( 250, 150, 165, 20 );
+    m_buttonSonarFrontKA = new Fl_Light_Button( 250, 310, 165, 20 );
     if ( m_buttonSonarFrontKA )
     {
         m_buttonSonarFrontKA->label( "Sonar Front Alive" );
@@ -502,7 +641,7 @@
         m_buttonSonarFrontKA->callback( &SonarFrontKeepAliveCB );
     }
 
-    m_textSonarFront = new Fl_Box( 250, 180, 165, 20 );
+    m_textSonarFront = new Fl_Box( 250, 340, 165, 20 );
     if ( m_textSonarFront )
     {
         m_textSonarFront->box( FL_THIN_DOWN_BOX );
@@ -510,42 +649,42 @@
         m_textSonarFront->label( "0F00 0F00 0F00 0F00" );
     }
 
-    m_sliderSonarFrontL = new Fl_Slider( 250, 210, 35, 100 );
+    m_sliderSonarFrontL = new Fl_Slider( 250, 370, 35, 100 );
     if ( m_sliderSonarFrontL )
     {
         m_sliderSonarFrontL->label( "Left" );
         m_sliderSonarFrontL->slider( FL_UP_BOX );
-        m_sliderSonarFrontL->bounds( 0x0fff, 0 );
+        m_sliderSonarFrontL->bounds( 0xff, 0 );
         m_sliderSonarFrontL->value( SonarFrontStatus::sonarFrontLeft() );
         m_sliderSonarFrontL->callback( SonarFrontSliderLeftCB, this );
     }
 
-    m_sliderSonarFrontCL = new Fl_Slider( 293, 210, 35, 100 );
+    m_sliderSonarFrontCL = new Fl_Slider( 293, 370, 35, 100 );
     if ( m_sliderSonarFrontCL )
     {
         m_sliderSonarFrontCL->label( "C Left" );
         m_sliderSonarFrontCL->slider( FL_UP_BOX );
-        m_sliderSonarFrontCL->bounds( 0x0fff, 0 );
+        m_sliderSonarFrontCL->bounds( 0xff, 0 );
         m_sliderSonarFrontCL->value( SonarFrontStatus::sonarFrontCenterLeft() );
         m_sliderSonarFrontCL->callback( SonarFrontSliderCenterLeftCB, this );
     }
 
-    m_sliderSonarFrontCR = new Fl_Slider( 336, 210, 35, 100 );
+    m_sliderSonarFrontCR = new Fl_Slider( 336, 370, 35, 100 );
     if ( m_sliderSonarFrontCR )
     {
         m_sliderSonarFrontCR->label( "C Right" );
         m_sliderSonarFrontCR->slider( FL_UP_BOX );
-        m_sliderSonarFrontCR->bounds( 0x0fff, 0 );
+        m_sliderSonarFrontCR->bounds( 0xff, 0 );
         m_sliderSonarFrontCR->value( SonarFrontStatus::sonarFrontCenterRight() );
         m_sliderSonarFrontCR->callback( SonarFrontSliderCenterRightCB, this );
     }
 
-    m_sliderSonarFrontR = new Fl_Slider( 380, 210, 35, 100 );
+    m_sliderSonarFrontR = new Fl_Slider( 380, 370, 35, 100 );
     if ( m_sliderSonarFrontR )
     {
         m_sliderSonarFrontR->label( "Right" );
         m_sliderSonarFrontR->slider( FL_UP_BOX );
-        m_sliderSonarFrontR->bounds( 0x0fff, 0 );
+        m_sliderSonarFrontR->bounds( 0xff, 0 );
         m_sliderSonarFrontR->value( SonarFrontStatus::sonarFrontRight() );
         m_sliderSonarFrontR->callback( SonarFrontSliderRightCB, this );
     }
@@ -565,6 +704,7 @@
         createServoSliders();
         createDisplays();
         createActionButtons();
+        createImuControls();
         createSonarFrontControls();
 
         m_window->show();
@@ -757,19 +897,40 @@
 
 // ----------------------------------------------------------------------------------------
 
+void SimDisplay::updateImuValues()
+{
+    Fl::lock();
+
+    if ( m_textImuValues )
+    {
+        char buf[ 80 ];
+        snprintf( buf, sizeof( buf ), "%3.1lf  %3.1lf  %3.1lf",
+                  ImuStatus::imuYaw(),
+                  ImuStatus::imuPitch(),
+                  ImuStatus::imuRoll() );
+        m_textImuValues->label( buf );
+    }
+
+    Fl::flush();
+
+    Fl::unlock();
+}
+
+// ----------------------------------------------------------------------------------------
+
 void SimDisplay::updateSonarFrontValues()
 {
     Fl::lock();
 
-    unsigned left        = SonarFrontStatus::sonarFrontLeft();
-    unsigned centerLeft  = SonarFrontStatus::sonarFrontCenterLeft();
-    unsigned centerRight = SonarFrontStatus::sonarFrontCenterRight();
-    unsigned right       = SonarFrontStatus::sonarFrontRight();
+    uint8_t left        = SonarFrontStatus::sonarFrontLeft();
+    uint8_t centerLeft  = SonarFrontStatus::sonarFrontCenterLeft();
+    uint8_t centerRight = SonarFrontStatus::sonarFrontCenterRight();
+    uint8_t right       = SonarFrontStatus::sonarFrontRight();
 
     if ( m_textSonarFront )
     {
         char buf[ 80 ];
-        snprintf( buf, sizeof( buf ), "%04X %04X %04X %04X",
+        snprintf( buf, sizeof( buf ), "%02X  %02X  %02X  %02X",
                   left, centerLeft, centerRight, right );
         m_textSonarFront->label( buf );
     }
--- a/main/robots/odr-sim/SimDisplay.h	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/SimDisplay.h	Thu Apr 17 22:03:28 2014 -0700
@@ -37,6 +37,7 @@
 #include <Poco/Timer.h>
 
 class Fl_Box;
+class Fl_Dial;
 class Fl_Double_Window;
 class Fl_Hor_Slider;
 class Fl_Light_Button;
@@ -57,6 +58,7 @@
         void updateManagerMsg( const char* msg, int length );
         void doMgrHeartbeat();
         void resetMgrHeartbeat();
+        void updateImuValues();
         void updateSonarFrontState( bool enabled );
         void updateSonarFrontValues();
 
@@ -78,6 +80,11 @@
         Fl_Light_Button*  m_buttonMotorCtl;
         Fl_Toggle_Button* m_buttonA;
         Fl_Toggle_Button* m_buttonB;
+        Fl_Light_Button*  m_buttonImuKA;
+        Fl_Box*           m_textImuValues;
+        Fl_Dial*          m_dialImuHeading;
+        Fl_Slider*        m_sliderImuPitch;
+        Fl_Slider*        m_sliderImuRoll;
         Fl_Light_Button*  m_buttonSonarFrontKA;
         Fl_Slider*        m_sliderSonarFrontL;
         Fl_Slider*        m_sliderSonarFrontCL;
@@ -92,6 +99,7 @@
         void createServoSliders();
         void createDisplays();
         void createActionButtons();
+        void createImuControls();
         void createSonarFrontControls();
         void timeoutMgrHeartbeat( Poco::Timer& timer );
 };
--- a/main/robots/odr-sim/SonarFrontStatus.cpp	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/SonarFrontStatus.cpp	Thu Apr 17 22:03:28 2014 -0700
@@ -84,10 +84,10 @@
 
 Poco::RWLock SonarFrontStatus::sm_rwLock;
 bool         SonarFrontStatus::sm_isEnabled   = false;
-unsigned     SonarFrontStatus::sm_left        = 0x0f00;
-unsigned     SonarFrontStatus::sm_centerLeft  = 0x0f00;
-unsigned     SonarFrontStatus::sm_centerRight = 0x0f00;
-unsigned     SonarFrontStatus::sm_right       = 0x0f00;
+uint8_t      SonarFrontStatus::sm_left        = 0xdf;
+uint8_t      SonarFrontStatus::sm_centerLeft  = 0xdf;
+uint8_t      SonarFrontStatus::sm_centerRight = 0xdf;
+uint8_t      SonarFrontStatus::sm_right       = 0xdf;
 
 // ----------------------------------------------------------------------------------------
 
@@ -115,7 +115,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-unsigned SonarFrontStatus::sonarFrontLeft()
+uint8_t SonarFrontStatus::sonarFrontLeft()
 {
     Poco::RWLock::ScopedReadLock lock( sm_rwLock );
     return sm_left;
@@ -123,7 +123,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-unsigned SonarFrontStatus::sonarFrontCenterLeft()
+uint8_t SonarFrontStatus::sonarFrontCenterLeft()
 {
     Poco::RWLock::ScopedReadLock lock( sm_rwLock );
     return sm_centerLeft;
@@ -131,7 +131,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-unsigned SonarFrontStatus::sonarFrontCenterRight()
+uint8_t SonarFrontStatus::sonarFrontCenterRight()
 {
     Poco::RWLock::ScopedReadLock lock( sm_rwLock );
     return sm_centerRight;
@@ -139,7 +139,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-unsigned SonarFrontStatus::sonarFrontRight()
+uint8_t SonarFrontStatus::sonarFrontRight()
 {
     Poco::RWLock::ScopedReadLock lock( sm_rwLock );
     return sm_right;
@@ -147,7 +147,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-void SonarFrontStatus::setSonarFrontLeft( unsigned value )
+void SonarFrontStatus::setSonarFrontLeft( uint8_t value )
 {
     Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
     sm_left = value;
@@ -155,7 +155,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-void SonarFrontStatus::setSonarFrontCenterLeft( unsigned value )
+void SonarFrontStatus::setSonarFrontCenterLeft( uint8_t value )
 {
     Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
     sm_centerLeft = value;
@@ -163,7 +163,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-void SonarFrontStatus::setSonarFrontCenterRight( unsigned value )
+void SonarFrontStatus::setSonarFrontCenterRight( uint8_t value )
 {
     Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
     sm_centerRight = value;
@@ -171,7 +171,7 @@
 
 // ----------------------------------------------------------------------------------------
 
-void SonarFrontStatus::setSonarFrontRight( unsigned value )
+void SonarFrontStatus::setSonarFrontRight( uint8_t value )
 {
     Poco::RWLock::ScopedWriteLock lock( sm_rwLock );
     sm_right = value;
--- a/main/robots/odr-sim/SonarFrontStatus.h	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/SonarFrontStatus.h	Thu Apr 17 22:03:28 2014 -0700
@@ -32,6 +32,8 @@
 #ifndef BCDRL_ROBOTS_ODRSIM_SONARFRONTSTATUS_H
 #define BCDRL_ROBOTS_ODRSIM_SONARFRONTSTATUS_H
 
+#include <stdint.h>
+
 #include <Poco/Event.h>
 #include <Poco/Runnable.h>
 #include <Poco/RWLock.h>
@@ -44,14 +46,14 @@
         static bool     isSonarFrontEnabled();
         static void     setSonarFrontEnabled();
         static void     setSonarFrontDisabled();
-        static unsigned sonarFrontLeft();
-        static unsigned sonarFrontCenterLeft();
-        static unsigned sonarFrontCenterRight();
-        static unsigned sonarFrontRight();
-        static void     setSonarFrontLeft( unsigned value );
-        static void     setSonarFrontCenterLeft( unsigned value );
-        static void     setSonarFrontCenterRight( unsigned value );
-        static void     setSonarFrontRight( unsigned value );
+        static uint8_t  sonarFrontLeft();
+        static uint8_t  sonarFrontCenterLeft();
+        static uint8_t  sonarFrontCenterRight();
+        static uint8_t  sonarFrontRight();
+        static void     setSonarFrontLeft( uint8_t value );
+        static void     setSonarFrontCenterLeft( uint8_t value );
+        static void     setSonarFrontCenterRight( uint8_t value );
+        static void     setSonarFrontRight( uint8_t value );
 
     public:
         SonarFrontStatus();
@@ -65,10 +67,10 @@
     private:
         static Poco::RWLock sm_rwLock;
         static bool         sm_isEnabled;
-        static unsigned     sm_left;
-        static unsigned     sm_centerLeft;
-        static unsigned     sm_centerRight;
-        static unsigned     sm_right;
+        static uint8_t      sm_left;
+        static uint8_t      sm_centerLeft;
+        static uint8_t      sm_centerRight;
+        static uint8_t      sm_right;
 
     private:
         Poco::Event m_quitEvent;
--- a/main/robots/odr-sim/jamfile	Thu Apr 17 22:01:14 2014 -0700
+++ b/main/robots/odr-sim/jamfile	Thu Apr 17 22:03:28 2014 -0700
@@ -37,6 +37,7 @@
     : main.cpp
       ODRSimApp.cpp
       ControllerStatus.cpp 
+      ImuStatus.cpp
       Receiver.cpp 
       SimDisplay.cpp 
       SonarFrontStatus.cpp