Click here to Skip to main content
Click here to Skip to main content

UltraDynamo

, 28 Nov 2012
Rate this:
Please Sign up or sign in to vote.
Ultrabook vehicle dynamo

Introduction

This article is a conceptual look at a proposed application to demonstrate the potential of the sensory devices embedded within the ultrabooks.

For those of you who enjoy motor-sport, and maybe watch the likes of the Forumla 1, you will have probably noticed the on-screen graphics of vehicle performance.

Modern sports cars, such as the Nissan GT-R also have onboard visual displays to convey the vehicle performance to the driver.

What if you are a track day fanatic, or just a general petrol head or gear head (or whatever you call them in your area), what if you could just take your ultrabook into the car, secure on the dash etc and then have it display performance characteristics?

Well that is the concept behind this app. (And yes, I am a petrol head!)

What are the aims of this app

Using the GPS sensors, accelerometer, inclinometers etc, it should be possible to display information to the vehicle occupants such as acceleration/deceleration data, positional data, and if you know the vehicles + occupants weight, it should be possible to calculate power characteristics.

Some of the statistics that you should be capable of displaying are;

1: Acceleration/deceleration

2: Cornering G

3: 0 to 60 (62mph) / 100 km/h (or custom)

4: 0 to 100 to 0

5: Quarter mile (or custom)

6: Sure there are others!

Using the GPS data, it should also be possible to map the data over your favourite mapping tools such as Google maps/earth

Data can also be stored for historical reference, or comparison between vehicles or following modifications.

Displays

The data could potentially be displayed in a number of formats, e.g. numerical data, bar graphs, line graphs, analogue dials.

It may also be possible to allow the user to build custom dashboards to present the data as they see fit.

Using the code

Project Update 1 (24th October 2012):

I have been dipping in an out of this project over the last week, when I can. The main coding effort is going to take place when I get home in a weeks time, but that will leave things a bit tight for the next deadline, so need to be doing something now!

Initially I am developing the code using Visual Studio 2012 Pro on a standard laptop, so have no way to test the sensors so had to come up with a suitable approach that could allow for the UI to be tested regardless of the underlying hardware. Can't wait to get my hands on the ultrabook to actually see if things move in the right direction etc!

After initially creating a blank Winforms C# application, I had to modify the project file to allow access to the Windows 8 Sensor APIs. This is covered in several articles, but in essence, you need to add a new property group to the project file containing;

<propertygroup />
    <targetplatformversion />8.0</targetplatformversion />
</propertygroup />

After doing this, you can then add suitable references to the runtime files; Windows.Devices.Sensors.dll and System.Runtime.InteropServices.WindowsRuntime.dll.

Sensor Wrappers

As mentioned above, I need a way to test the UI without having access to the live sensor data. In order to achieve this I created some wrapper classes that act as a middle-man between the UI and the actual sensors. This allows me to enable a Simulate Mode and inject test data into the code. Also, If any sensor is not available, that particular sensor is automatically switched to simulate mode. So far, I have created wrappers for the AmbientLightSensor, Accelerometer, Compass, Gyrometer and Inclinometer. Still have to look at the GPS sensor.

Below is what the wrapper MyLightSensor looks like;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Sensors;

namespace UltraDynamo.Sensors
{
    public class MyLightSensor
    {        
        public static bool Available { get; private set; }
        public static bool Simulated { get; private set; }

        public static float LightReading {get; private set; }
        public static float rawLightReading {get; private set; }
        public static float simLightReading {get; private set; }

        //Source Sensor
        private static LightSensor lightSensor;

        //Events
        public static event ChangeHandler Change;
        public static EventArgs e = null;
        public delegate void ChangeHandler(MyLightSensor sender, EventArgs e);

        public MyLightSensor()
        {            
            //Base sensor
            lightSensor = LightSensor.GetDefault();

            if (lightSensor != null)
            {
                setAvailable(true);
                setSimulated(false);

                lightSensor.ReadingChanged += lightSensor_ReadingChanged;
            }
            else
            {
                setAvailable(false);
                setSimulated(true);
            }
        }

        void lightSensor_ReadingChanged(LightSensor sender, LightSensorReadingChangedEventArgs args)
        {
             //throw new NotImplementedException();
            rawLightReading = args.Reading.IlluminanceInLux;
            if (!Simulated)
            {
                setLightLevel(rawLightReading);
            }

            //raise event
            if (Change != null)
                Change(this, e);
        }

        private void setLightLevel(float value)
        {
            LightReading = value;
        }

        private void setAvailable(bool available)
        {
            Available = available;

            //RaiseEvent
            if (Change != null)
                Change(this, e);
        }

        public void setSimulated(bool simulated)
        {
            Simulated = simulated;

            //RaiseEvent
            if (Change != null)
                Change(this, e);
        }

        public void setSimulatedValue(float value)
        {
            simLightReading = value;

            if (Simulated)
            {
                setLightLevel(simLightReading);
            }

            //RaiseEvent
            if (Change != null)
                Change(this, e);
        }
    }
}

As you can see, there are a number of static properties, that show if the Sensor is currently Simulated and/or Available, as well as the Used, Raw and Simulated values. A couple of methods are provided to set simulated data values and switch modes between Simulated and Live. In the code, you can also see the private static field that is the actual sensor where the live data is accessed, as well as a change event for tracking sensor data updates.

Sensor Simulation Controller

After creating the sensor wrappers, the next step was to create a number of Forms that can be used to manipulate the sensor data. The image below shows the simulate form created for the Inclinometer;

Sensor Data Pesentation

Having the data available now, I have started to create UserControls that can be dropped into any part of the application, either on standalone forms so the user can customise the lay out, or onto pre-defined dashboards. Below shows the three user controls created for the Inclinometer's Pitch, Roll and Yaw and show the data represented in the simulate form above.

Graphics are not one of my strong areas, so I have used some crude image manipulation just to get the core functionality working, and can go back and enhance things with future updates. You will also notice on the forms above the status blobs on the top left and top right. The top left blue blob is a flag that the data is Simulated. The blob on the top right shows the real sensor status, Red=Unavailable, Green=Available.

Another control that has been created is a compass rose indicator, this is shown below;

If we now take a look at one of the simpler controls, the CompassHeading control, this takes the Compass Heading and converts the numerical value to either of "N, NE, E, SE, S, SW, W, NW". You can see how this control listens to events from the Sensor wrapper;

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using UltraDynamo.Sensors;

namespace UltraDynamo.Controls
{
    public partial class UICompassHeadingLetters : UserControl
    {
        //Source Compass
        MyCompass myCompass;
        
        public UICompassHeadingLetters()
        {
            InitializeComponent();

            //Initialise a compass
            myCompass = new MyCompass();

            //Track changes on the compass
            //Add a compass to the mainform
            MyCompass.Change += new MyCompass.ChangeHandler(myCompass_Change);
            myCompass_Change(myCompass, new EventArgs());

        }

        void myCompass_Change(MyCompass sender, EventArgs e)
        {
            this.Refresh();
        }

        private void UICompassHeadingLetters_Paint(object sender, PaintEventArgs e)
        {
            String output = "N"; //Default to North removes need for two ifs below
            //Get the string representation of the heading
            double heading = MyCompass.Heading;

            if (heading >= 22.5 && heading < 67.5)
                output = "NE";

            if (heading >= 67.5 && heading < 112.5)
                output = "E";

            if (heading >= 112.5 && heading < 157.5)
                output = "SE";

            if (heading >= 157.5 && heading < 202.5)
                output = "S";

            if (heading >= 202.5 && heading < 247.5)
                output = "SW";

            if (heading >= 247.5 && heading < 292.5)
                output = "W";

            if (heading >= 292.5 && heading < 337.5)
                output = "NW";

            //Establish base fonts and graphics objects
            Graphics g = e.Graphics;

            Font f = this.Font;
            Font newFont = this.Font;
            SizeF testSize;
            float fHeight=0;
            float fWidth=0;
            bool fontGood = true;
            
            for (int newSize = 1; fontGood; newSize++)
            {
                //Increase the size and test height again)
                newFont=new Font(f.Name,newSize,f.Style);
                testSize = g.MeasureString(output,newFont);
            
                //Determine boundary size for the text
                fHeight = testSize.Height;
                fWidth = testSize.Width;

                //Test the text height and width against control size
                if ((fHeight > (this.Height)) | (fWidth > (this.Width)))
                {
                    fontGood = false;
                    newSize--;  //go back by 1 size, recalculate size required for positioning central on control
                    if (newSize <6 ) { newSize=6;};
                    newFont = new Font(f.Name,newSize,f.Style);
                    testSize = g.MeasureString(output,newFont);
                    fHeight = testSize.Height;
                    fWidth = testSize.Width;
                }
            }            

            //Draw the text heading on the control
            g.DrawString(output, newFont, Brushes.Green, new Point((this.Width - (int)fWidth) / 2, (this.Height - (int)fHeight) / 2));

            if (MyCompass.Simulated)
                g.FillEllipse(Brushes.Blue, 0, 0, 5, 5);

            //Add a Red/Green dot to show sensor availability in top right corner
            if (MyCompass.Available)
                g.FillEllipse(Brushes.Green, this.Width - 5, 0, 5, 5);
            else
                g.FillEllipse(Brushes.Red, this.Width - 5, 0, 5, 5);

        }
    }
}

The next stages of the development are to look at some real time trends, analog gauge dials and some of the other planned functionality as mentioned in the initial outline brief.

That is the end of the Update 1. So far so good (I think!).

Project Update 2 (13th November 2012):

Things have been a bit chaotic over the last couple of weeks working on this application.

There have been numerous problems encountered, and given the time frame, everything feels a bit rushed to get it "out the door". Some of the issues encountered are;

  • Typical cross threading problems
  • Sensors eventing conflicts
  • Inherent bugs in hardware/software
  • Code Signing and package creation

So where am I with things?

There was a big rewrite of some of the eventing to combat the cross threading problems. I still want to further improve this area, but can't risk breaking things at this stage. So maybe for a later date.

The simulation code shown above, was great for the initial testing, but given the rewrite of the sensor stuff, it no longer works, so has been tucked away in the background until it can be revisited as a later date.

There also appears to be a bug with the GPS subsystem at a hardware/driver level. So unfortunately cannot fully test or implement the features in the introduction list until this issue is resolved. However, application still has useful functionality for an initial release.

A basic overview dashboard has been created which shows all the main sensor elements, as well as a net horsepower gauge. The HP is calculated by using the accelerometer and the vehicle vehicle (and occupants) weight. This is Net HP and does not take into account for drivetrain losses or drag losses. These can maybe be factored in at a later date. The dashboard is shown below;

There are also a number of realtime trends that show you has been going on, for example, the one below is the accelerometer trend.

Had problems getting a 'free' code signing certificate through and still waiting for the validation call. So went on my own and got one through GlobalSign. That then introduced the problem of how to setup up VisualStudio to build the packages, code sign them in the post-build events. InstallShield was all new to me as well, so getting everything to package up nicely, sign the installers etc. was a bit of a headache. This was followed by some pain of actually getting my hands on the MSI installer from setup wrapper.

Plenty things to possibly write about at a later date, but in the meantime, I think my heads bust, and that concludes Update 2!

Project Update 3 (28th November 2012):

After all the hassle with submitting the app on the 14th, then the weeks delay waiting for it to be published, I just wanted to add a little update as I noticed I hadn't really mentioned it elsewhere already. In the dashboard display above, you will notice that the right hand dial indicator is displaying Net Horespower. This is a calculated figure that is based on a) The vehicle weight b) the Acceleration and c) the vehicle speed. If you refer to the wikipedia article  http://en.wikipedia.org/wiki/Horsepower and look at the calculations for the drawbar horsepower you can see how they relate to each other.

James Watt introduced this unit of power in the 18th century and he stated that 1 horsepower was the power required to lift a 550lb weight in 1 second. It is possible to calculate this using the parameters shown and data from the Ultrabook sensors as;

Net HP = (Weight (in lbs) x Acceleration (g) x Speed (mph) ) / 375

The weight is provided by the user on the configuration page of the application, the other data is sensor derived. The 375 is a constant derived from the conversion of the 550 lb/second to miles per hour.

It would be easy to add in calculated constants for drivetrain losses and drag coefficients, but that is a job for another day.

After I had published the App, I noticed on the controls and displays, I had forgot to enable "double buffering", so there is a bit of a flicker during updates. Since publishing, I have already also began to rework the eventing system and various other parts of the application so hopefully get them out and released in a future update.

Other Blue Sky Idea

It may also be possible to further extend the core functionality to interface with the vehicles OBDII or CAN bus to make use of other reference data, e.g. vehicle parameters like speed, gear, throttle angles,

This is is beyond the initial scope, but just a thought.

Points of Interest

This should provide plenty of research opportunity into the features of the ultrabooks and provide something interesting to get my teeth into.

History

  • 13th October 2012 - First draft of conceptual app description
  • 24th October 2012 - Project Update 1 added.
  • 13th November 2012 - Project Update 2 added.
  • 28th November 2013 - Project Update 3 added.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

DaveAuld
Engineer
Scotland Scotland
I have been working in the Oil & Gas Industry for over 20 years now.
 
Core Discipline is Instrumentation and Control Systems.
 
Completed Bsc Honours Degree (B29 in Computing) with the Open University in 2012.
 
Currently, Offshore Installation Manager for the Beryl Bravo platform, which is located ~180 miles NE of Aberdeen, Scotland in the Northern North Sea.
Formely on the Forties Charlie platform, which is located ~110Miles NE of Aberdeen.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralAccuracy PinmemberUberMeistro14-Jan-13 19:31 
GeneralRe: Accuracy PinmentorDaveAuld14-Jan-13 20:44 
QuestionMy vote of 5!! PinmemberAbhishek Nandy7-Dec-12 18:05 
AnswerRe: My vote of 5!! PinmentorDaveAuld7-Dec-12 23:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 28 Nov 2012
Article Copyright 2012 by DaveAuld
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid