Introduction to (part of) IBM Watson

Recently, I joined the IBM Watson beta program (you can join too here) to see what it had to offer.  It looks like IBM is using the “Watson” word to cover a broad array of analytical and machine learning capabilities.  One area that Watson is used is to do statistical analysis without knowing any programming and/or statistics.  For example, I went into their portal and uploaded a new dataset that I just got from the Town Of Cary regarding traffic stops:

image image

image

I then hit the “New Exploration” button just to see what would happen and voila, I have graphs!

image 

image

image

 

So this is kind interesting, they seem to use both modeling sweeping and parameter sweeping and then use natural language questions to explore the dataset.  This is quite impressive as it allows someone to who nothing about statistics to ask questions and get answers.  I am not sure if there is a way to drill down into the models to tweet the questions nor does there look to be a way to consume the results.  Instead, it looks like a management dashboard.  So it is a bit like when you view the results of a dataset, they have taken it to the n degree.

I then went back and hit the “Create a Prediction” button

image

I picked a random y variable (“disposition) with the default values and voila, graphs:

image

Interestingly, it does some sweeping and it picked up that the PrimaryKey is correlated with date – which would make sense since the date is part of the PK value :-)

image

In any event, I think this is a cool entry into the machine learning space from IBM.  They really have done a good job in making data science accessible.  Now, if they could put their weight into “Open Data” so there are lots of really cool datasets to analyze available, they would really position themselves well in an emerging market.  I can’t wait to dig in even more with  Watson…

Using IBM’s Watson With F#

 

I think everyone is aware of IBM’s Watson from its appearance on Jeopardy.  Apparently, IBM has made the Watson Api available for developers if you sign up here.  Well, there goes my Sunday morning!  I signed up and after one email confirm later, I was in. 
IBM has tied Watson to something called “Blue Mix”, which looks to be a full-service suite of applications from deployment to hosting .  When I looked at the api documentation here, I decided to use the language translation service as a good “hello world” project.  Looking at the api help page, I was hoping just to make a request and get a response with a auth token in the header, like every other api in the world.  However, the documentation really leads you down a path of installing the Watson Explorer on your local machine, and a create a blue mix project, etc.. 
Fortunately, the documentation has some pointers to other projects where people have made their own app.  I used thisthis one as a model and set up Fiddler like so

image

The authorization token is the username and password separated by a colon encoded to base 64.
Sure enough, a 200

image

Setting it up in #FSharp was a snap
1 #r @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll" 2 #r @"..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll" 3 4 open System 5 open System.Net.Http 6 open System.Net.Http.Headers 7 open System.Net.Http.Formatting 8 open System.Collections.Generic 9 10 11 let serviceName = "machine_translation" 12 let baseUrl = "http://wex-mt.mybluemix.net/resources/translate" 13 let userName = "youNameHere@aol.com" 14 let password = "yourPasswordHere" 15 let authKey = userName + ":" + password 16 17 let client = new HttpClient() 18 client.DefaultRequestHeaders.Authorization <- new AuthenticationHeaderValue("Basic",authKey) 19 20 let input = new Dictionary<string,string>() 21 input.Add("text","This is a test") 22 input.Add("sid","mt-enus-eses") 23 let content = new FormUrlEncodedContent(input) 24 25 let result = client.PostAsync(baseUrl,content).Result 26 let resultContent = result.Content.ReadAsStringAsync().Result

And sure enough

image

 

You can see the gist here
So with that simple call/request under my belt, I decided to look at the api that everyone is talking about, the question/answer api.  I fired up Fiddler again and took a look at the docs.  After some tweaking of the Uri, I got a successful request/response:

image

image

With the answers to an empty question kind interesting. if not head-scratching:

image

So passing in a question:

image

image

So we are cooking with gas.  Back into FSI

1 #r @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll" 2 #r @"..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll" 3 4 open System 5 open System.Net.Http 6 open System.Net.Http.Headers 7 open System.Net.Http.Formatting 8 open System.Collections.Generic 9 10 11 let baseUrl = "http://wex-qa.mybluemix.net/resources/question" 12 let userName = "yourName@aol.com" 13 let password = "yourCreds" 14 let authKey = userName + ":" + password 15 16 let client = new HttpClient() 17 client.DefaultRequestHeaders.Authorization <- new AuthenticationHeaderValue("Basic",authKey) 18 19 let input = new Dictionary<string,string>() 20 input.Add("question","what time is it") 21 let content = new FormUrlEncodedContent(input) 22 23 let result = client.PostAsync(baseUrl,content).Result 24 let resultContent = result.Content.ReadAsStringAsync().Result

With the result like so

image

And since it is Json coming back, why not use the type provider?

1 let client = new HttpClient() 2 client.DefaultRequestHeaders.Authorization <- new AuthenticationHeaderValue("Basic",authKey) 3 4 let input = new Dictionary<string,string>() 5 input.Add("question","How can I quit smoking") 6 let content = new FormUrlEncodedContent(input) 7 8 let result = client.PostAsync(baseUrl,content).Result 9 let resultContent = result.Content.ReadAsStringAsync().Result 10 11 type qaResponse = JsonProvider<".\QAResponseJson.json"> 12 let qaAnswer = qaResponse.Parse(resultContent) 13 14 qaAnswer.Question.Answers 15 |> Seq.ofArray 16 |> Seq.iter(fun a -> printfn "(%s)" a.Text)

Here is Watson’s response:

image

You can see the gist here

Predicting Physician Gender Using AzureML and F#

I am working with a couple of friends in a 2 week hackathon where the main subject is health care provider quality.  One of the datasets that we are using is the national registry of physician information found here.  One of the team members loaded it into Azure Sql Server and it is a dog.  It is a about 1 gig of data and takes a couple of minutes to scan the entire dataset.  I decided to take a small slice of the data (Connecticut physicians) and do some analysis on it .

My first step was to bring the data into AzureML via the Data Reader

image

Note that it took about 3 minutes to bring the data down.  I then saved this data as a local dataset to do my experiments:

image

I then fired up another experiment using the dataset as the base.  I first dragged in a Project Column module to only grab the columns I was interested in

image image

I then pulled in a Missing Values Scrubber module where I would drop any row where there was a value missing

image image

I then brought in a Metadata Editor module To change all of the fields to Categorical data types

image image

With the data ready to go, I created a 70/30 (train/test) split of the data and added a Multiclass Decision Forest model with Gender as the Dependent variable

image image

I then added a Score Model module and fed in the 30%.  I finally added an Evaluate Model module

 image

And the results were interesting, if not unsurprising:

image

Basically, if I know your age, your specialty, and your medical school, we can predict if you are a man 85% of the time.  Encouragingly, we can only do it 62% of the time for a woman.   I then published the experiment and created a quick script to consume the data:

1 #r @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll" 2 #r @"..\packages\Microsoft.AspNet.WebApi.Client.5.2.2\lib\net45\System.Net.Http.Formatting.dll" 3 4 open System 5 open System.Net.Http 6 open System.Net.Http.Headers 7 open System.Net.Http.Formatting 8 open System.Collections.Generic 9 10 type scoreData = {FeatureVector:Dictionary<string,string>;GlobalParameters:Dictionary<string,string>} 11 type scoreRequest = {Id:string; Instance:scoreData} 12 13 let invokeService () = async { 14 let apiKey = "" 15 let uri = "https://ussouthcentral.services.azureml.net/workspaces/19a2e623b6a944a3a7f07c74b31c3b6d/services/6c4bbb43456e4d7e8a9196f2899f717d/score" 16 use client = new HttpClient() 17 client.DefaultRequestHeaders.Authorization <- new AuthenticationHeaderValue("Bearer",apiKey) 18 client.BaseAddress <- new Uri(uri) 19 20 let input = new Dictionary<string,string>() 21 input.Add("Gender","U") 22 input.Add("MedicalSchoolName","OTHER") 23 input.Add("GraduationYear","1995") 24 input.Add("PrimarySpecialty","INTERNAL MEDICINE") 25 26 let instance = {FeatureVector=input; GlobalParameters=new Dictionary<string,string>()} 27 let scoreRequest = {Id="score00001";Instance=instance} 28 29 let! response = client.PostAsJsonAsync("",scoreRequest) |> Async.AwaitTask 30 let! result = response.Content.ReadAsStringAsync() |> Async.AwaitTask 31 32 if response.IsSuccessStatusCode then 33 printfn "%s" result 34 else 35 printfn "FAILED: %s" result 36 response |> ignore 37 } 38 39 invokeService() |> Async.RunSynchronously

And I have a way of predicting genders:

U,OTHER,1995,INTERNAL MEDICINE,0.651031798112075,0.348968201887925,0,F

Using Git With Visual Studio

I am starting to use Git with Visual Studio 2013 on my home projects.  I have been using Git lightly for pushing code samples into GitHub, but never on projects with other people.  This is a pretty good set of articles about setting up Git with Visual Studio and well worth the read before doing it (like who reads instructions). 

I created a project on Visual Studio Online and selected Git as the source control.  I then cloned the empty project locally.  Next, I created a brand-new Web Api 2 solution in Visual Studio and pushed the files over to that repository.  I then pushed those changes up to VSO.  Finally, I went over to another machine and cloned the repository and pulled down the files.

This was all well and good until I made a change on one machine and I wanted to pull down the changes into the solution that I had open on the other machine.  I was getting an “uncommitted changed being overwritten by merge” exception.  The frustrating thing was that there was nothing in the Visual Studio 2013 tooling/add-ins that allowed me to discard my local changes.  I wrote this post to stack overflow and it turns out I had a problem because I made the mistake of adding file to the repository that I didn’t want to.  I needed to do this –> add the .suo file to gitIgnore BEFORE committing the 1st change.  The problem was that adding it to the gitIgnore after the commit means the file was still being tracked and there is nothing in the out of the box VS2013 tools that can help you resolve the problem. 

The best advice from SO was to use git extensions because when I installed it, I could do all of the things I wanted to do without learning the git commands.  Indeed, I installed it and holy cow, this is awesome:

image

Implementing (Parts Of) ASP.NET Identity Using F#

I started working though this and this article for implementing security in a new Web Api 2 site I am spinning up.  Everything is working out OK – not great but better than prior ASP.NET implementations I have done.  I do think the ASP.NET team has made security better and I am really excited about token based security.  My biggest gripe is that there is still too much magic going on and it is still hard to introduce non-out of the box implementations.  For example, the sample code that you can add via Nuget has a placeholder for en email provider.  The article has the code for a specific implementation of a company called SendGrid (the sample is here and the email is here).
The CSharp implementation looks like this (I did add some constructor injection b/c I am opposed to touching the Configuration (or any part of the file system for that matter) outside of Main on sanity grounds):
1 public class SendGridEmailProvider: IIdentityMessageService 2 { 3 String _mailAccount = String.Empty; 4 String _mailPassword = String.Empty; 5 String _fromAddress = String.Empty; 6 7 public SendGridEmailProvider(String mailAccount, String mailPassword, String fromAddress) 8 { 9 _mailAccount = mailAccount; 10 _mailPassword = mailPassword; 11 _fromAddress = fromAddress 12 } 13 14 public System.Threading.Tasks.Task SendAsync(IdentityMessage message) 15 { 16 var sendGridMessage = new SendGridMessage(); 17 sendGridMessage.From = new MailAddress(_fromAddress); 18 List<String> recipients = new List<string>(); 19 recipients.Add(message.Destination); 20 sendGridMessage.AddTo(recipients); 21 sendGridMessage.Subject = message.Subject; 22 sendGridMessage.Html = message.Body; 23 sendGridMessage.Text = message.Body; 24 25 var credentials = new NetworkCredential(_mailAccount, _mailPassword); 26 var transportWeb = new Web(credentials); 27 if (transportWeb != null) 28 return transportWeb.DeliverAsync(sendGridMessage); 29 else 30 return Task.FromResult(0); 31 } 32 }

I then decided to implement a SMS Text Provider along the same lines.  The 1st company I came to was CDyne but when I went to their sample code, they are still using a SOAP-based service and the last thing I wanted to do was to clutter up my project with all of the WSDL and files that you needs when consuming a service like that.
I then thought, this is stupid.  I might was well use FSharp type providers to do the implementation.  Less Code, less files, less clutter, more goodness.  I first swapped out the Email to a FSharp implementation:
1 type SendGridEmailService(account:string, password:string, fromAddress:string) = 2 interface IIdentityMessageService with 3 member this.SendAsync(identityMessage) = 4 let sendGridMessage = new SendGridMessage() 5 sendGridMessage.From = new MailAddress(fromAddress) |> ignore 6 let recipients = new List<string>() 7 recipients.Add(identityMessage.Destination) 8 sendGridMessage.AddTo(recipients) 9 sendGridMessage.Subject <- identityMessage.Subject 10 sendGridMessage.Html <- identityMessage.Body 11 sendGridMessage.Text <- identityMessage.Body 12 13 let credentials = new NetworkCredential(account, password) 14 let transportWeb = new Web(credentials) 15 match transportWeb with 16 | null -> Task.FromResult(0):> Task 17 | _ -> transportWeb.DeliverAsync(sendGridMessage)

I then did a SMS text provider using type providers.
1 type cDyneService = Microsoft.FSharp.Data.TypeProviders.WsdlService<"http://sms2.cdyne.com/sms.svc?wsdl"> 2 3 type CDyneSMSService(licenseKey:Guid) = 4 interface IIdentityMessageService with 5 member this.SendAsync(identityMessage) = 6 let cDyneClient = cDyneService.Getsms2SOAPbasicHttpBinding 7 let client = cDyneService.Getsms2SOAPbasicHttpBinding() 8 match client with 9 | null -> Task.FromResult(0):> Task 10 | _ -> client.SimpleSMSsendAsync(identityMessage.Destination,identityMessage.Body,licenseKey):> Task

Compared to a CSharp implementation, this is joyous.  Less noise, more signal.  And thanks to Lee on Stack Overflow for helping with the upcast of Task…

Adopting F# in a C# Shop

I have been speaking to different groups in both large and small companies about adopting FSharp as part of their .NET stack and the resistance ranges from the understandable to the head-scratching.  I posted a similar question to the Google group here and got some pretty interesting responses.  The funniest was this video.  Scott Wlaschin offers several convincing reasons to use FSharp here  as well as  several ways to try and work around the walls thrown up in a “C Sharp shop” here.

I have recently implemented a project using FSharp in a large insurance company that is a  “CSharp shop” using the following technique and hopefully someone else can get some use out of it.  My first premise is that FSharp is not the end, it is the means.  Therefore, you don’t want to walk into any meeting and say something like “hey, I heard of this great new language, we should try it out.”  That kind of statement will be dead in the water with the layers of project managers, architectural review committees, etc….  Rather, you need to walk into the meeting and way “As you know, our company is supposed to be ‘innovative’ and I have been experimenting outside of work with different ways to reduce the number of bugs in our code and deliver software faster.”

(Jamie note, since I wrote this, this study came out pointing out that functional programming does produce better code quality.  However, its benefits are not as important as having a high performing team with the appropriate process (team size, project size, and commit size)).  One more thing to mention to the PM.

The next step is to realize that one of the most overlooked benefits of FSharp is that since it is a .NET language, you can slide a FSharp project into a Visual Studio Solution with just a couple of button clicks and the existing CSharp code will just work with it.  Use this to your advantage by creating an interface to an existing CSharp class that has some conditional logic.  For example,CSharp implementation of a class that creats a customer for an order

1 public class CustomerCreator 2 { 3 Boolean alreadyHasAnAccount = false; 4 5 public Customer CreateCustomerForAnOrder(Order order, String firstName, String lastName) 6 { 7 //Actual implementation is not important 8 return new Customer(); 9 } 10 }

 

The actual implementation is not important because as a FSharp dev, you don’t really want to look at the CSharp code.  All you really want  to do is extract the interface:

image

1 interface ICustomerCreator 2 { 3 Customer CreateCustomerForAnOrder(Order order, string firstName, string lastName); 4 }

With the interface in place, you can now create a FSharp project in the solution and begin your implementation of it:

1 namespace ChickenSoftware.CustomerManagementExt 2 3 open ChickenSoftware.CustomerManagement 4 5 type BetterCustomerCreator() = 6 interface ICustomerCreator with 7 member this.CreateCustomerForAnOrder(order, firstName, lastName) = 8 new Customer()

(Note I wouldn’t call it ‘BetterCustomerCreator’ for real, even if it is better). 

You then can enter your next meeting saying, something like “I created functional equivalence with the enhancements of fewer bug, better readability, and mutli-threading support.”  The PM will say, “that is awesome” and the developers who no longer code (typically called architects in large companies) will protest that it is in a different language.  But now you have the PM on your side and you can have a discussion about finding qualified people to work in F#.  My experience there is that the developers you want to work with will jump at the chance and the devs you don’t want on the project will balk at learning a new language/mindset.  You can also mention that the really good C# devs are already using linq an lambdas so they are already transitioning to FSharp.

The last point is that you need to back up the statement you made originally that FSharp reduces the number of bugs and delivers software faster.  If you are a .NET dev,  I would recommend listening to Bob Martin when he says that you need to spend 20 hours a week outside of your primary job (as he mentions here) and learning a functional language (as he mentions here) learning FSharp.  That effort, coupled with the FSharp community (the best community you will find) will certainly allow you to walk the walk.  There will be detractors at every turn who will point to any slowdown to a FSharp codebase as proof that CSharp would have been perfectly fine.  The only thing I can say there is “Don’t let the turkeys get you down.” and manage expectations that FSharp is not a silver bullet and that there are places where CSharp is more appropriate.  Be the voice of innovation and reason, don’t be the functional dogmatic in the room.  So far it was worked for me, and I hope it works for you.

Halloween Project (Garage Of Mystery)

For this years Halloween, the kids and I decided to do something out of the opening scene of Indiana Jones, without the big rock.  We wanted to give kids a choice when they came to the house –> either get a small “fun” size candy bar or enter the garage of mystery for the chance of a full sized candy bar.  (Incidentally, whoever thought it would be a good idea to name the smallest candy size on earth “fun” obviously was never a kid.  When I was growing up, we called it four size, being that if took four of them to make a normal candy bar)

So if the kid wants to go into the garage of mystery, they have to get to the alter of snickers without the motion detector or the laser beam trip wires catching them.  The full-size Snickers would disappear if the kid was picked up by the Kinect motion detector or if they tripped too many beams.  In the diagram below, the red dots are the lasers crossing in front of the alter

image

The first thing we did was construct the alter.  

imageimage

Once the frame was set, we added a servo with a trap door to the top.  We control the servo via a Phidget Servo Controller with some basic code from the Phidget SDK (if the SDK, you know, had F# in it)

1 member this.servoController_Attached(args:Events.AttachEventArgs) = 2 let _servoController = args.Device :?> AdvancedServo 3 _servoController.servos.[0].Engaged <- true 4 _servoController.servos.[0].Position <- 110. 5 _isServoControllerReady <- true 6 7 member this.initializeController() = 8 _servoController.Attach.Add(this.servoController_Attached) 9 _servoController.``open``() 10 11 member this.moveController(position:float) = 12 if _isServoControllerReady then 13 _servoController.servos.[0].Position <- position 14

And you can see it in action here:

 

With the alter ready, we turned our attention to the laser trip wires.  We purchased a whole bunch of dollar store pen lasers and got some Phidget light sensors.  We then created a frame for both sides of the garage –> one to mount the laser and 1 to mount the light sensor

imageimage

And then we added some basic code from the Phidget SDK (if the SDK, you know, had F# in it)

1 member this.interfaceKit_Attached(args: Events.AttachEventArgs) = 2 let _interfaceKit = args.Device :?> InterfaceKit 3 _interfaceKit.sensors 4 |> Seq.cast 5 |> Seq.map(fun s -> s :> InterfaceKitAnalogSensor) 6 |> Seq.map(fun s -> s.Sensitivity <- 20) 7 |>ignore 8 _isInterfaceKitReady <- true 9 10 member this.interfaceKit_SensorChange(e: SensorChangeEventArgs ) = 11 let eventArgs = new LightSensorChangeEventArgs(e.Index,e.Value) 12 lightSensorChange.Trigger(eventArgs) 13 14 member this.initializeInterfaceKit() = 15 _interfaceKit.Attach.Add(this.interfaceKit_Attached) 16 _interfaceKit.SensorChange.Add(this.interfaceKit_SensorChange) 17 _interfaceKit.``open``() 18 _interfaceKit.waitForAttachment() 19

Note that we are trapping the event from the light sensor and then raising it up in our own event. 

With the light sensor in place, we turned our attention to the Kinect motion sensor.  I first considered Rob Miles’s ides to compare the different color frames to see if there was movement but because I am using F# and F# does not support pointers like C#, the performance was too choppy.  You can see the Stack Overflow thread here.  So I could have either jumped to over to C# or figure out a different way using F#.  I went with option B by using the skeleton frame, which has a Z index.  By comparing the Z index over time, I can see how fast a person is moving towards to alter.  The Kinect code was pretty much from the SDK (if the SDK, you know, had F# in it)

1 member this.kinectSensor_ColorFrameReady(args: ColorImageFrameReadyEventArgs) = 2 use colorFrame = args.OpenColorImageFrame() 3 if not (colorFrame = null) then 4 let colorData = Array.zeroCreate<byte> colorFrame.PixelDataLength 5 colorFrame.CopyPixelDataTo(colorData) 6 let width = colorFrame.Width 7 let height = colorFrame.Height 8 let stride = colorFrame.Width * colorFrame.BytesPerPixel 9 let eventArgs = new ColorDataReadyEventArgs(colorData,width,height,stride) 10 colorDataReady.Trigger(eventArgs) 11 () 12 13 member this.KinectSensor_SkeletonFrameReady(args: SkeletonFrameReadyEventArgs) = 14 use skeletonFrame = args.OpenSkeletonFrame() 15 if not (skeletonFrame = null) then 16 let skeletons = Array.zeroCreate<Skeleton> skeletonFrame.SkeletonArrayLength 17 skeletonFrame.CopySkeletonDataTo(skeletons) 18 let skeletons1 = skeletons |> Array.filter (fun s -> s.TrackingState = SkeletonTrackingState.Tracked) 19 if skeletons1.Length > 0 then 20 skeletonChanged.Trigger(skeletons1.[0]) 21 () 22 () 23 24 member this.initializeKinect() = 25 _kinectSensor.ColorStream.Enable() 26 _kinectSensor.ColorFrameReady.Subscribe(this.kinectSensor_ColorFrameReady) |> ignore 27 _kinectSensor.SkeletonStream.Enable(); 28 _kinectSensor.SkeletonFrameReady.Subscribe(this.KinectSensor_SkeletonFrameReady) |> ignore 29 _kinectSensor.Start() 30

In the UI, I then checked for the skeleton movement and if the person moved too fast, they would trigger the snickers trap door to open

1 void garage_SkeletonChanged(object sender, Skeleton skeleton) 2 { 3 if(_skeletonPoint.Z > 0) 4 { 5 float zDelta = _skeletonPoint.Z - skeleton.Position.Z; 6 if (zDelta >= _zDeltaThreshold) 7 { 8 _numberOfSkeletonHits += 1; 9 skeletonChangedProgressBar.Dispatcher.Invoke(new Action(() => skeletonChangedProgressBar.Value = _numberOfSkeletonHits)); 10 11 } 12 if(_numberOfSkeletonHits >= _numberOfHitsForAlarm) 13 { 14 _garage.moveController(_openPosition); 15 } 16 17 skeletonCanvas.Children.Clear(); 18 drawSkelton(skeleton); 19 } 20 _skeletonPoint = skeleton.Position; 21 } 22

With the result like this:

With the hard parts done, it was time to create a UI.  I went with C# here because I am using WPF and the support for WPF and the Kinect is best in C#.  I created a WPF application and built a UI

1 <Window x:Class="ChickenSoftware.Halloween.UI.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="600" Width="650" > 5 <Grid Height="600" Width="650" VerticalAlignment="Top" HorizontalAlignment="Left" > 6 <Image Name ="kinectVideo" Height="480" Width="640" Margin="10,0,0,120" /> 7 <Canvas Name="skeletonCanvas" Height="480" Width="640" Margin="10,0,0,120" /> 8 <Rectangle x:Name="sensor0Rectange" Fill="Lime" HorizontalAlignment="Left" Height="40" Margin="10,480,0,0" Stroke="Black" VerticalAlignment="Top" Width="82"/> 9 <Rectangle x:Name="sensor1Rectange" Fill="Lime" HorizontalAlignment="Left" Height="40" Margin="189,480,0,0" Stroke="Black" VerticalAlignment="Top" Width="83"/> 10 <Rectangle x:Name="sensor2Rectange" Fill="Lime" HorizontalAlignment="Left" Height="40" Margin="367,480,0,0" Stroke="Black" VerticalAlignment="Top" Width="82"/> 11 <Rectangle x:Name="sensor3Rectange" Fill="Lime" HorizontalAlignment="Left" Height="40" Margin="537,480,0,0" Stroke="Black" VerticalAlignment="Top" Width="83"/> 12 <ProgressBar x:Name="skeletonChangedProgressBar" HorizontalAlignment="Left" Height="40" Margin="10,528,0,0" VerticalAlignment="Top" Width="392" Foreground="#FFB00606"/> 13 <Button x:Name="resetButton" Content="Reset" HorizontalAlignment="Left" Height="37" Margin="537,528,0,0" 14 VerticalAlignment="Top" Width="83" Click="resetButton_Click"/> 15 <Button x:Name="EjectButton" Content="Eject!" HorizontalAlignment="Left" Height="37" Margin="429,528,0,0" 16 VerticalAlignment="Top" Width="83" Click="EjectButton_Click"/> 17 </Grid> 18 </Window>

I then added some code to handle all of the events that the Phidgets and Kinect are sending to the UI and do something useful with it.    For example, the light sensor change fills in the appropriate box on the screen (note that Phidgets use a different thread so you need to use Dispatcher.Invoke)

1 void garage_LightSensorChange(object sender, LightSensorChangeEventArgs args) 2 { 3 switch (args.SensorIndex) 4 { 5 case 0: 6 if (args.SensorIndex == 0 && args.LightAmount < _lightSensorThreshold) 7 { 8 _sensor0Tripped = true; 9 sensor0Rectange.Dispatcher.Invoke(new Action(()=>sensor0Rectange.Fill = new SolidColorBrush(Colors.Red))); 10 } 11 break; 12 case 1: 13 14 if (args.SensorIndex == 1 && args.LightAmount < _lightSensorThreshold) 15 { 16 _sensor1Tripped = true; 17 sensor1Rectange.Dispatcher.Invoke(new Action(() => sensor1Rectange.Fill = new SolidColorBrush(Colors.Red))); 18 } 19 break; 20 case 2: 21 if (args.SensorIndex == 2 && args.LightAmount < _lightSensorThreshold) 22 { 23 _sensor2Tripped = true; 24 sensor2Rectange.Dispatcher.Invoke(new Action(() => sensor2Rectange.Fill = new SolidColorBrush(Colors.Red))); 25 } 26 break; 27 case 3: 28 if (args.SensorIndex == 3 && args.LightAmount < _lightSensorThreshold) 29 { 30 _sensor3Tripped = true; 31 sensor3Rectange.Dispatcher.Invoke(new Action(() => sensor3Rectange.Fill = new SolidColorBrush(Colors.Red))); 32 } 33 break; 34 } 35 CheckForIntruder(); 36 } 37

With this associated method

1 private void CheckForIntruder() 2 { 3 Int32 numberOfSensorsTripped = 0; 4 5 if (_sensor0Tripped == true) 6 numberOfSensorsTripped += 1; 7 if (_sensor1Tripped == true) 8 numberOfSensorsTripped += 1; 9 if (_sensor2Tripped == true) 10 numberOfSensorsTripped += 1; 11 if (_sensor3Tripped == true) 12 numberOfSensorsTripped += 1; 13 if (numberOfSensorsTripped >= _numberOfSensorsForAlarm ) 14 _garage.moveController(0); 15 16 }

This code would be so much better in F# using pattern matching but b/c of the UI code, I kept it in C#.  I might refactor the non-visual components later.  The one thing that did surprise me is that how the Kinect V1 SDK makes it very hard to separate the UI components from the domain components.  Phidgets, on the other hand, had a very clear separation of concerns

So we then added some sides to the alter of snickers

image

And we were good to go.  The final result looks like this (the smoke machine was an added touch):

All of the code is on github here.  If you create your own garage of mystery, please drop me a line –> I would love to see what other makers come up with. 

Follow

Get every new post delivered to your Inbox.