antimeme / rotpi

Republic of Techies Meetup Repository
MIT License
0 stars 0 forks source link

Develop the Raspberry Pi logic for turning on or off the LED. #3

Closed jorgelr617 closed 9 years ago

jorgelr617 commented 9 years ago

Suspense Date: Next Meetup (July 25th)

KevinGage commented 9 years ago

@jorgelr617 @mikegomezg @antimeme @JohnnyRobotic I had a thought about the led controller functions. I read your spec and for the most part I agree but had a slightly different thought on delay. Would something like the pseudo code below work?

ledBatch(ledArray, stateArray, delayArray) { do stuff }

so you could issue a list of sequential commands and delays like this. ledBatch([1,2,3,1,2,3], [on,on,on,off,off,off], [0,0,0,1,2,3])

This would turn on lights 1,2,3 at the same time because the delay is zero. Then it would turn lights 1,2,3 off, while delaying light 1 for 1 second, light 2 for 2 seconds, light 3 for 3 seconds.

Make sense? Or did you have something else in mind?

antimeme commented 9 years ago

I like the idea of a function that supports LED combinations with delays, but what's been proposed will get unwieldy when the number of elements get larger. We can easily use JSON for structured data, so why not something like this:

ledBatch([{delay: 0, led1: true, led2: true, led3: true}, {delay: 1, led1: false}, {delay: 2, led2: false}, {delay: 3, led3: false]);

It's more verbose, but it's much easier to follow what's going on from inspection of the code. I've also used booleans rather than "on" and "off" since that's likely to be easier to manage and "on" === "true" seems intuitive enough.

KevinGage commented 9 years ago

That makes sense. I had considered json as an alternative to 3 arrays but I hadn't thought about this approach exactly. My mind was going in the direction that the server doesn't really need to process large batches of instructions and the client could just do much of the logic. If the server needs to blink 3 times just send 3 blink requests :) Your idea is very flexible though so I think I'll go that route. I'll change the functions that I already wrote to use bool and I'll work on this new function.

jorgelr617 commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

I'm not following. Before coding, let's agree on the specs. I think that we need to make a distinction in terms of what the (a) user enters (like a command) in the client, (b) how it gets transported to the server and (c) how the server implements it.

Kevin, is what you're discussing for a, b or c? For (a), let's not use the term function and let's use the term "command" instead. By command, I mean the commands that the user enters in the webpage UI (text area) to control the LEDs in the circuit board.

What I'm hearing from Jeff is that he wants to use JSON for the commands? Right? Makes sense to me. The only thing I don't agree is with "true and false" versus "on and off". From a Human Factor Engineering (HFE) perspective, I think "on and off" make more sense. Also, can we keep the syntax simple? Why "ledbatch"? Why not just "led" and then determine from the arguments whether it is a batch or not. Here's the way I see the syntax in the client:

a) Example 1: batch

led [{delay: 0, led1: on}, {delay: 0, led3: on}, {delay: 1, led1: off}, {delay: 2, led2: off}, {delay: 3, led3: off}]

b) Example 2: single LED led {delay: 1, led1: off}

c) Example 3: Same as #1 command (and same results), but not a batch but individual commands

led {delay: 0, led1: on} led {delay: 0, led3: on} led {delay: 1, led1: off} led {delay: 2, led2: off} led {delay: 3, led3: off}

jorgelr617 commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

I'm not following. Before coding, let's agree on the specs. I think that we need to make a distinction in terms of what the (a) user enters (like a command) in the client, (b) how it gets transported to the server and (c) how the server implements it.

Kevin, is what you're discussing for a, b or c? For (a), let's not use the term function and let's use the term "command" instead. By command, I mean the commands that the user enters in the webpage UI (text area) to control the LEDs in the circuit board.

What I'm hearing from Jeff is that he wants to use JSON for the commands? Right? Makes sense to me. The only thing I don't agree is with "true and false" versus "on and off". From a Human Factor Engineering (HFE) perspective, I think "on and off" make more sense. Also, can we keep the syntax simple? Why "ledbatch"? Why not just "led" and then determine from the arguments whether it is a batch or not. Here's the way I see the syntax in the client:

a) Example 1: batch

led [{delay: 0, led1: on}, {delay: 0, led3: on}, {delay: 1, led1: off}, {delay: 2, led2: off}, {delay: 3, led3: off}]

b) Example 2: single LED led {delay: 1, led1: off}

c) Example 3: Same as Example 1 command (and same results), but not a batch but individual commands

led {delay: 0, led1: on} led {delay: 0, led3: on} led {delay: 1, led1: off} led {delay: 2, led2: off} led {delay: 3, led3: off}

KevinGage commented 9 years ago

tldr :) I went ahead and updated the controller. I'll review your message tomorrow and see if we can come to a compromise. Thanks!

KevinGage commented 9 years ago

@mikegomezg @antimeme @JohnnyRobotic @amurray22 @jorgelr617 Jorge, I am speaking about step c (how the server implements it). I think that for this bool probably does make the most sense for light states. true = on, false = off. If you want to impliment on/off instead off boolean values in the user interface that makes sense too and should not be a problem.

I think that I have come up with a good way to handle these requests. Let me know if the following idea makes sense. Again this is step c (server processing), not what the client will see.

'command' led can take an arbitraty number of arguments, with the minimum being 1 javascript object, and one callback function. The callback function will take a single argument which will accept and returned errors.

like this led({delay:0, 17: true, 19: false}, cb(er){})

You can pass as many objects as you want. So it could look like this led({delay:0, 17: true, 19: false}, {delay:5, 17:false, 19:false}, cb(er){})

delay can represent the number of seconds (or milliseconds if we want) to delay before running the commands in that object. Each number represents a gpio pin on the pi that is connected to a LED. Each bool represents on or off.

If we want to abstract the gpio pins into strings like 'led1' I think it makes sense to do it somewhere else in the program. Maybe in our http server. That way if we ever want to re-use this controller code for another purpose, or we change the pins that have LEDs connected we don't need to worry about led names. The pins on the board will never change.

If this makes sense to everyone I can probably make it happen tonight. I have the lights blinking on my pi so it should just be a matter of a few changes to make it fit this style.

antimeme commented 9 years ago

Kevin, I think milliseconds is better for the interface since seconds may be too course. I'm not sure if we'll have millisecond precision in practice though. Maybe the user interface should use seconds, since that's more human friendly, but it can support things like 2.5 seconds, within some reasonable limit of precision. What do you think?

On Wed, Jul 15, 2015 at 8:54 AM, KevinGage notifications@github.com wrote:

@mikegomezg https://github.com/mikegomezg @antimeme https://github.com/antimeme @JohnnyRobotic https://github.com/JohnnyRobotic @amurray22 https://github.com/amurray22 @jorgelr617 https://github.com/jorgelr617 Jorge, I am speaking about step c (how the server implements it). I think that for this bool probably does make the most sense for light states. true = on, false = off. If you want to impliment on/off instead off boolean values in the user interface that makes sense too and should not be a problem.

I think that I have come up with a good way to handle these requests. Let me know if the following idea makes sense. Again this is step c (server processing), not what the client will see.

'command' led can take an arbitraty number of arguments, with the minimum being 1 javascript object, and one callback function. The callback function will take a single argument which will accept and returned errors.

like this led({delay:0, 17: true, 19: false}, cb(er){})

You can pass as many objects as you want. So it could look like this led({delay:0, 17: true, 19: false}, {delay:5, 17:false, 19:false}, cb(er){})

delay can represent the number of seconds (or milliseconds if we want) to delay before running the commands in that object. Each number represents a gpio pin on the pi that is connected to a LED. Each bool represents on or off.

If we want to abstract the gpio pins into strings like 'led1' I think it makes sense to do it somewhere else in the program. Maybe in our http server. That way if we ever want to re-use this controller code for another purpose, or we change the pins that have LEDs connected we don't need to worry about led names. The pins on the board will never change.

If this makes sense to everyone I can probably make it happen tonight. I have the lights blinking on my pi so it should just be a matter of a few changes to make it fit this style.

— Reply to this email directly or view it on GitHub https://github.com/antimeme/rotpi/issues/3#issuecomment-121605908.

KevinGage commented 9 years ago

The program can support milliseconds, but like you said in practical use it's just going to do it's best, it won't be precise. Which i think is fine. I'll make the function accept milliseconds and we'll just keep in mind when writing client code not to expect perfect precision on the timing.

mikegomezg commented 9 years ago

I added a diagram to the repo that might help how we think about controlling the LEDs. A client could send an Instruction object to the server which consists of a series of on/off states and the delays involved in moving each LED through each state.

KevinGage commented 9 years ago

Here is what the command would look like to do exactly what you have explained in the diagram using our proposed method. led({delay:0, 0:true, 1:true, 2:true}, {delay:1000, 0:false}, {delay:1000,1:false}, {delay:0, 2:false}, {delay:1000, 0:true}, {delay:4000, 1:true}, cb(err){})

mikegomezg commented 9 years ago

led( [ state1: { {0:true, delay:0}, {1:true, delay:0}, {2:true, delay:0},
}, state2: { {0:false, delay:1}, {1:false, delay:2}, {2:true, //no delay because state didn't change},
}, state3: { {0:true, delay:1}, {1:true, delay:5}, {2:false, delay:0},
}, ], cb(err){})

So my idea is an array of states, with delays for all LED's that have changed from the previous state. Maybe we're thinking of the same thing, just specifying it differently. The change I'm adding is that we can't move to the next state object until all the delays in the previous state object have been processed.

KevinGage commented 9 years ago

I think we are basically on the same page. We are both thinking a series of batch commands. Your approach is based around the next state of each light. I think either method would work but I think the one we previously listed might have some small advantages. You can look at the command and easily see what the lights will all do in sequence. Also you never need to make a 'non-change'. When a light is turned on it will remain on until you turn it off and vice versa. In your state 2 you are running code for light 2 that essentially doesn't do anything. Maybe I just like the flow of the other method because it's how I think. If your method is more intuitive for everyone we can go that route.

jorgelr617 commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

Awesome discussion! I like where this is heading towards. Mike, thank you for the diagram.

Continuing to talk about (c). I think that we need to separate the interface from the implementation. In this case, the command is the function signature that Kevin is developing. Kevin, I like the interface (command/function signature) that you're proposing except for returning the error callback function. What's the benefit from that? Couldn't you just throw the appropriate exception and let the caller handle it? Please ensure that you return specific errors. Can you please confirm this? In other words, if the LED # is incorrect, return that specific error. If the delay value is incorrect, please return that specific error. In other words, don't return compound errors, like "pin # or delay value is wrong" because the caller can't take specific actions based on a generic error.

I vote for milliseconds. I vote for on/off instead of true/false in the function signature. I'm not sure what you gain with true/false. You can always map on/off to true/false in the function signature to your implementation. By the way, can the LEDS be dimmed? In that case, I would use a percentage, like 40, 0 (off) or 100 (full on).

I think that we should have a MeetUp this week. I'll be in the Braintree library Sat @ 1- 3 PM if anyone is interested discussing the project. I also think that we need some informal RoEs (Rules of Engagement) so that we can collaborate better. For example, not implementing something until we agree to the interface and specs. Give folks an opportunity of one day to comment or vote on a decision (such as interface). Etc.

KevinGage commented 9 years ago

I like the concept of a callback function. This way you can send a command to the server and use the callback function to do something when the command is done executing in an asynchronous manner. I have found that using a callback that takes an error is a pretty standard way of doing things in nodejs. I could just as easily throw an exception but I don't see the advantage. I have been trying to make the error messages as specific as possible. I guess I'll pause on actually doing any work until we can agree on approach. I probably can not come saturday because I will most likely be working.

jorgelr617 commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

OK, callback function makes sense. You have my vote. What about dimming LEDs?

KevinGage commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

Not sure. I think we would need to be able to control voltage on the IO pins. By default they send 3.3v when on and 0v when off. The node package we are using right now only supplies the on and off options. Details here https://www.npmjs.com/package/onoff I don't know if the pi hardware could support variable voltage using another package or if we would need to control it with hardware components. Right now with my tests I need a resistor between each LED and the pi because 3.3v will smoke a standard LED.

mikegomezg commented 9 years ago

Kevin, I like your method for specifying the changes in LED lights. Maybe we can incorporate my approach in the UI and have it generate commands in the syntax you specified.

KevinGage commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22 Now I'm second guessing my method. I've been thinking in terms of the most efficient server calls. I've been testing by just running scripts so my method would work well. Your concept ties to a users web interface better. If we used your method on the client end then what's the point of converting in the middle? Why not just pass your info to the server and have it run the logic? I'll have to keep thinking about this. I guess I've just had tunnel vision on the server portion so far and wasn't thinking big picture. If anyone else has thoughts please jump in. In the meantime I have time tonight so I'll probably write the method that I described just as practice. If we throw it out I'm cool with that. I just want to make some LED lights blink to kill some time

jorgelr617 commented 9 years ago

@KevinGage @mikegomezg @antimeme @JohnnyRobotic @amurray22

For the command interface (User Interface), I'll go back to what I proposed. I'm concerned that Mike's proposal is too verbose. Here's what I'm recommending. It's simple and intuitive. Please read these examples and read afterwards.

a) Example 1: batch

led [{delay: 0, led1: on}, {delay: 0, led3: on}, {delay: 1, led1: off}, {delay: 2, led2: off}, {delay: 3, led3: off}]

b) Example 2: single LED led {delay: 1, led1: off}

c) Example 3: Same as Example 1 command (and same results), but not a batch but individual commands

led {delay: 0, led1: on} led {delay: 0, led3: on} led {delay: 1, led1: off} led {delay: 2, led2: off} led {delay: 3, led3: off}

Kevin, a good design practice is to separate interface from implementation. I don't agree with the statement "Why not just pass your info to the server and have it run the logic". Here's how I see the Client-Server "workflow":

  1. User enters command(s) in Client UI (For example: led {delay: 1, led1: off}).
  2. User clicks submit button on the Client UI.
  3. Client encodes the command in a message in JSON and sends it to the Server with WebSockets or Socket.io framework.
  4. Server receives message and decodes it.
  5. Server logs the received of the Client message.
  6. Server beings processing message. When processing the Client command inside the message, it identifies that this is an LED command and has 1 argument {delay: 1, led1: off}. (In the future, there'll be other commands than just LED, like controlling sound.)
  7. Server then calls Kevin's appropriate function with the argument(s) passed in.
  8. Server then executes Kevin's LED function.
  9. Server updates the graphics in the Server LED page to show the status of the Circuit board.
  10. During steps 1-9, Server is listening for other Client messages also.
mikegomezg commented 9 years ago

However we decide to implement this functionality, from a users perspective I think it makes sense to think of the problem in terms of a series of states, with the delays determining how long it takes for each LED to "catch up" to the specified state.

If an LED doesn't change, maybe we can just not include it in the command.

You could think of the following code as saying, "in order to get to state2, turn LED 0 off after 1 second, and then turn LED 1 off after 2 seconds. And since Led 2 is already on, don't do anything to it."

state2: [ {0:false, delay:1}, {1:false, delay:2} ]

jorgelr617 commented 9 years ago

@mikegomezg

Mike, I'm not following why you want to add the word "state" in the command. It makes the command verbose. I'ts already implicit in the command. What do you gain by adding it?

mikegomezg commented 9 years ago

That's true. The number is fine by itself. I just included the string before it for clarity.

I'm curious what @antimeme thinks about this problem of what syntax to use to control the LEDs through time.

KevinGage commented 9 years ago

@antimeme @mikegomezg @JohnnyRobotic @amurray22 @jorgelr617 I rewrote the controller to work with the method that I proposed. Again I want to mention this is just for fun so if we throw it away and start over I'm fine with that. I'll show how it works using Jorges case examples.

a) Example 1: batch

led( {delay: 0, 1:true, 3:true}, {delay: 1000, 1: false}, {delay: 2000, 2: false}, {delay: 3000, 3: false}, cb(err){})

b) Example 2: single LED led ({delay: 1000, 1: false}, callback(err){})

c) Example 3: Same as Example 1 command (and same results), but not a batch but individual commands

led ({delay: 0, 1: true}, callback(err){}) led ({delay: 0, 3: true}, callback(err){}) led ({delay: 1000, 1: false}, callback(err){}) led ({delay: 2000, 2: false}, callback(err){}) led ({delay: 3000, 3: false}, callback(err){})

edit: forgot i also changed to milliseconds

KevinGage commented 9 years ago

@mikegomezg @antimeme @JohnnyRobotic @amurray22 @jorgelr617

cool sideways video demo :) https://drive.google.com/file/d/0B6JmKqU3aVSZSno3TEZHR0o1Sm8/view?usp=sharing

jorgelr617 commented 9 years ago

@mikegomezg @antimeme @JohnnyRobotic @amurray22 @KevinGage

I can't see the demo. Here's what I see when I click on your link:

image

JohnnyRobotic commented 9 years ago

Proxy problems again?

Bill Sprague

From: jorgelr617 notifications@github.com Sent: Jul 15, 2015 8:21 PM To: antimeme/rotpi Cc: Bill Sprague Subject: Re: [rotpi] Develop the Raspberry Pi logic for turning on or off the LED. (#3)

@mikegomezghttps://github.com/mikegomezg @antimemehttps://github.com/antimeme @JohnnyRobotichttps://github.com/JohnnyRobotic @amurray22https://github.com/amurray22 @KevinGagehttps://github.com/KevinGage

I can't see the demo. Here's what I see when I click on your link:

[image]https://cloud.githubusercontent.com/assets/11369378/8712825/304df528-2b2f-11e5-8cb5-c6e49a8bca63.png

Reply to this email directly or view it on GitHubhttps://github.com/antimeme/rotpi/issues/3#issuecomment-121788314.

KevinGage commented 9 years ago

@mikegomezg @antimeme @JohnnyRobotic @amurray22 @jorgelr617 https://drive.google.com/open?id=0B6JmKqU3aVSZSno3TEZHR0o1Sm8 Try this link

antimeme commented 9 years ago

Nice work! On Jul 15, 2015 20:16, "KevinGage" notifications@github.com wrote:

@mikegomezg https://github.com/mikegomezg @antimeme https://github.com/antimeme @JohnnyRobotic https://github.com/JohnnyRobotic @amurray22 https://github.com/amurray22 @jorgelr617 https://github.com/jorgelr617

cool sideways video demo :)

https://drive.google.com/file/d/0B6JmKqU3aVSZSno3TEZHR0o1Sm8/view?usp=sharing

— Reply to this email directly or view it on GitHub https://github.com/antimeme/rotpi/issues/3#issuecomment-121786253.

KevinGage commented 9 years ago

I changed this one more time. Before I was using a variable amount of arguments like this led(arg1, arg2, arg3, cb) I think building these calls would be unnecessarily tricky.

So the only difference now is that the led command takes two argument, the first an array and the second a callback. Like this, led([arg1, arg2, arg3], cb) I think these will be easier to build.

Everything else is the same, error handeling was updated to deal with the array