/// <summary> /// Runs one of the abstract samples using physical ports of an Netduino 3 board. /// </summary> public static void Main() { AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2 shield; #if Sample01SimpleBlinker // Sample 01: Blink a LED: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample01SimpleBlinkerDistributed // Sample 01 again, but this time blinking several LEDs at once simply by distributing the output to them // using a BooleanOutputDistributor object, which on itself implements IBooleanOutput and simply passes the // Values to an arbitrary number of outputs: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new BooleanOutputDistributor( new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led))); #elif Sample01SimpleBlinkerAlternating // Sample 01 again, but this time blinking two LEDs alternating by using the BooleanOutputDistributor // combined with inverting one of the outputs using the BooleanOutputInverter, coded using the fluent API // that the corresponding extension method offers: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new BooleanOutputDistributor( new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led).Inverted(), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue).Inverted())); #elif Sample02SmoothPwmBlinker // Sample 02: Let a lamp blink smoothly. The abstract code just expects any IDoubleOutput and will cyle that // in small steps from 0.0 to 1.0 and back to 0.0 forever. As an example of an IDoubleOutput, we pass a // PWM-controlled pin: AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: new Netduino3.AnalogPwmOutput(DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPolling // Sample 03: Control a LED using a button: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPollingInvertingButton // Sample 03 again, but this time inverting the button simply by using a BooleanInputConverter, simply by // using the fluent API offered by the corresponding extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(DigitalInputPin.OnboardButton).Invert(), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPollingInvertingLamp // Sample 03 again, but this time inverting the lamp simply by using a BooleanOuputConverter, simply by // using the fluent API offered by the corresponding extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue).Inverted()); #elif Sample03ButtonControlsLampUsing2ButtonsWithAnd // Sample 03 again, but this time the lamp shall only light up if both of two buttons are pressed. // To use this sample, connect two closing buttons to the Netduino 3 input pins D0 and D1 with their other // ports connected to VSS (+5V). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new BooleanAndInput( new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D0), new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D1)), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampUsing2ButtonsWithOr // Sample 03 again, but this time the lamp shall light up if one or both of two buttons are pressed. // To use this sample, connect two closing buttons to the Netduino 3 input pins D0 and D1 with their other // ports connected to VSS (+5V). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new BooleanOrInput( new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D0), new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D1)), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampBlinking // Sample 03 again, but this time we let the lamp blink simply by using the BlinkedWhenTrueOutput class, // coded using the fluent API provided by extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample03ButtonControlsLampBlinkingSmoothly // Sample 03 again, but this time we let the lamp blink smoothly by using PWM and the SmoothedOutput class, // coded using fluent API (even if the Run() method does nothing than simply turn the "output" on when the // button is pressed). Read the definition of the lamp in reverse order: // - Incoming is simply the boolean signal of the button. // - This is made blink (BlinkedWhenTrue). // - This, still boolean, value gets mapped to the double number 0.0 for false and 1.0 for true // (MappedFromBoolean). // - This signal, which switches between 0.0 and 1.0, is then smoothed to slowly enlight or dimm the lamp // (Smoothed). // - This, finally, is fed into the AnalogPwmOutput controlling the LED. // So, using the fluent API for outputs is coded from back to front: Define the target output (here, the // PWM-controlled LED, that is an IDoubleOutput), and apply transformations until you get an "I(type)Output" // output where "(type)" matches the output type expected (here, an IBooleanOutput). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue) .Smoothed(valueChangePerSecond: 1.0f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample04ButtonControlsLampEventBased // Sample 04: Control a lamp using a button, but this time do not poll the status of the button, but react // to the ValueChanged event (that is, reacting on an IRQ generated by the µC whenever the status of the // button's input pin changed). AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample04ButtonControlsLampEventBasedInvertingButton // Sample 04 again: Control a lamp using a button using events, but with an inverted button using the // ObserverableBooleanInputInverter class, coded using the fluent API that the extension methods offer. AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(DigitalInputPin.OnboardButton).Invert(), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample04ButtonControlsLampEventBasedSmoothly // Sample 04 again, but let the LED blink smoothly just as in Sample03ButtonControlsLampBlinkingSmoothly. // We do the very same here: Convert the IBooleanOutput of the event based method to the smoothly blinking // IDoubleOutput for the PWM-controlled LED. It works all the same whether we use a polling IBooleanInput // or the IRQ/event-based variant IObservableBooleanInput for the button. The output possibillities are just // the same. AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue) .Smoothed(valueChangePerSecond: 1.0f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample05ControlLampBrightnessThroughAnalogInput // Sample 05: Let a LED light up just as bright (in the range from 0.0 to 1.0) as an analog input gives // values (also in the range from 0.0 to 1.0). Note that the input range is not scaled in any way in this // sample, but just goes straigt to the output. To run this sample, connect a variable resistor (such as a // photo cell) between anlog input pin A0 and GND (0V). Then, the lamp will light darker as more light goes // to the photo cell. AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample05ControlLampBrightnessThroughAnalogInputScaled // Sample 05 again, but this time auto-learn the actual incoming value range of the input and scale it to // the range from 0.0 to 1.0 using the ScaleToRangeInput class, coded using the fluent API of the // corresponding extension methods. This will cause the full range from 0.0 to 1.0 being used on the lamp, // regardless if, for example, the incoming values range only from 0.3 to 0.6. To run this sample, connect a // variable resistor (such as a photo cell) between anlog input pin A0 and GND (0V). AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0) .ScaleToRange(smallestValueMappedTo: 0.0f, largestValueMappedTo: 1.0f), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample05ControlLampBrightnessThroughAnalogInputScaledInverted // Sample 05 again, but this time the auto-learned ranged has swapped lower and upper limits. This results // in the lamp going brighter when the analog input signal gets lower (that is, the photo cell getting more // light, and vice versa. To run this sample, connect a variable resistor (such as a photo cell) between // anlog input pin A0 and GND (0V). AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0) .ScaleToRange(smallestValueMappedTo: 1.0f, largestValueMappedTo: 0.0f), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample06WaitForButtonPolling // Sample 06: Wait for an input to reach a specific value, or to change, using the WaitFor() and // WaitForChange() extension methods. In this sample, the button is used only as an IBooleanInput, so that // waiting will cause polling. See sample 07 for the exact same code, just using the butten as an // IObservableBooleanInput, working without polling. AbstractIO.Samples.Sample06WaitForButtonPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample07WaitForButtonEventBased // Sample 07: Nearly the same as sample 06, but using the button as an IObservableBooleanInput insted of // a plain IBooleanInput. This allows the WaitFor() and WaitForChange() methods to use IRQ events instead of // polling: AbstractIO.Samples.Sample07WaitForButtonEventBased.Run( button: new Netduino3.ObservableDigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample02LetMotorRun // Connect to the Adafruit V2 shield at its default address: shield = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(); // Use the sample controlling a lamp just control a motor, as both implement IDoubleOutput: AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: shield.GetDcMotor(1)); #elif Sample08LetManyMotorsRun // Control as many motors you whish on as many motor shields you whish simultaneously: // Let a lamp blink smoothly on a separate thread as a means to see how smooth all these operations can be // handled by the board: Thread blinkThread = new Thread( () => AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue))); blinkThread.Start(); // Run the sample, using as many motors as you like: // As additional ideas, suppose that: // - All motors can run on 9V, but one only on 6V. So we scale this motor's output by 6/9. // - One DC motor has its pins swapped and needs output in reverse polarity. So scale by a factor of -1. // Note that the Run() method does not know nor needs to know about this facts about the actual motors, and // that all we need to do is to pass scaled outputs using the fluent API to the Run() method. // // We pass 3 onboard LEDs to display the number of motors which are (still) accelerating or decelerating // as numbers 0, 1, 2 or greater than 2. // // We let the Run() method run on its own thread because blocking the main thread by waiting for // ManualResetEvents (as is done while the Run() method waits) would block the whole OS (as of 2018-05-05). var shield1 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(96); var shield2 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); var shield3 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(98); var shield4 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(99); Thread runner = new Thread(() => AbstractIO.Samples.Sample08SmoothManyAnalogOutputs.Run( new IBooleanOutput[] { new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led) }, shield1.GetDcMotor(1), shield1.GetDcMotor(2), shield1.GetDcMotor(3), shield1.GetDcMotor(4), shield2.GetDcMotor(1), shield2.GetDcMotor(2), shield2.GetDcMotor(3), shield2.GetDcMotor(4), shield3.GetDcMotor(1).Scaled(factor: 6.0f / 9.0f), shield3.GetDcMotor(2), shield3.GetDcMotor(3), shield3.GetDcMotor(4), shield4.GetDcMotor(1).Scaled(factor: -1.0f), shield4.GetDcMotor(2), shield4.GetDcMotor(3), shield4.GetDcMotor(4))); runner.Start(); for (; ;) { Thread.Sleep(10); } #elif Sample09SimpleStepperMotor // Let a stepper motor turn randomly: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(); //new Thread(() => // AbstractIO.Samples.Sample09SimpleStepperMotor.Run(shield.GetStepperMotor(1, 2, 8))) // .Start(); const float scale = 0.4f; new Thread(() => AbstractIO.Samples.Sample09SimpleStepperMotor.Run( new StepperMotor(shield.GetDcMotor(1).Scaled(scale), shield.GetDcMotor(2).Scaled(scale), 8))) .Start(); for (; ;) { Thread.Sleep(10); } #elif Sample10StepperMotorClock // Let a simple clock run by turning a stepper motor a given number of steps every minute: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); const float clockScale = 0.2f; new Thread(() => AbstractIO.Samples.Sample10StepperMotorClock.Run( stepper: new StepperMotor(phase1Output: shield.GetDcMotor(1).Scaled(clockScale), phase2Output: shield.GetDcMotor(2).Scaled(clockScale), stepsPerStepCycle: 4), stepsPerMinute: 4, pauseBetweenStepsInMs: 50)) .Start(); for (; ;) { Thread.Sleep(10); } #elif Sample11SimpleTrainWithDoors // Let a train run: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); AbstractIO.Samples.Sample11SimpleTrainWithDoors.Run( trainMotor: shield.GetDcMotor(1).Smoothed(valueChangePerSecond: 2.0f, rampIntervalMs: 20), train1ReachedBottomStation: new Netduino3.DigitalInput(DigitalInputPin.D0), train2ReachedBottomStation: new Netduino3.DigitalInput(DigitalInputPin.D1), doorMotor: shield.GetDcMotor(2), redLight: shield.GetDcMotor(3).MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f), greenLight: shield.GetDcMotor(4).MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f), waitForDoorsToMoveInMs: 4000, waitWithOpenDoorsInMs: 3000, waitAroundDoorOperationsInMs: 2000); #else #error Please uncomment exactly one of the samples. #endif }
/// <summary> /// Runs one of the abstract samples using physical ports of an Netduino 3 board. /// </summary> public static void Main() { // AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2 shield; #if Sample01SimpleBlinker // Sample 01: Blink a LED: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample01SimpleBlinkerDistributed // Sample 01 again, but this time blinking several LEDs at once simply by distributing the output to them // using a BooleanOutputDistributor object, which on itself implements IBooleanOutput and simply passes the // Values to an arbitrary number of outputs: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new BooleanOutputDistributor( new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led))); #elif Sample01SimpleBlinkerAlternating // Sample 01 again, but this time blinking two LEDs alternating by using the BooleanOutputDistributor // combined with inverting one of the outputs using the BooleanOutputInverter, coded using the fluent API // that the corresponding extension method offers: AbstractIO.Samples.Sample01SimpleBlinker.Run( lamp: new BooleanOutputDistributor( new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led).Inverted(), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue).Inverted())); #elif Sample02SmoothPwmBlinker // Sample 02: Let a lamp blink smoothly. The abstract code just expects any IDoubleOutput and will cyle that // in small steps from 0.0 to 1.0 and back to 0.0 forever. As an example of an IDoubleOutput, we pass a // PWM-controlled pin: AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: new Netduino3.AnalogPwmOutput(DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPolling // Sample 03: Control a LED using a button: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPollingInvertingButton // Sample 03 again, but this time inverting the button simply by using a BooleanInputConverter, simply by // using the fluent API offered by the corresponding extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(DigitalInputPin.OnboardButton).Invert(), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampPollingInvertingLamp // Sample 03 again, but this time inverting the lamp simply by using a BooleanOuputConverter, simply by // using the fluent API offered by the corresponding extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue).Inverted()); #elif Sample03ButtonControlsLampUsing2ButtonsWithAnd // Sample 03 again, but this time the lamp shall only light up if both of two buttons are pressed. // To use this sample, connect two closing buttons to the Netduino 3 input pins D0 and D1 with their other // ports connected to VSS (+5V). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new BooleanAndInput( new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D0), new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D1)), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampUsing2ButtonsWithOr // Sample 03 again, but this time the lamp shall light up if one or both of two buttons are pressed. // To use this sample, connect two closing buttons to the Netduino 3 input pins D0 and D1 with their other // ports connected to VSS (+5V). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new BooleanOrInput( new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D0), new Netduino3.DigitalInput(Netduino3.DigitalInputPin.D1)), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample03ButtonControlsLampBlinking // Sample 03 again, but this time we let the lamp blink simply by using the BlinkedWhenTrueOutput class, // coded using the fluent API provided by extension methods: AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample03ButtonControlsLampBlinkingSmoothly // Sample 03 again, but this time we let the lamp blink smoothly by using PWM and the SmoothedOutput class, // coded using fluent API (even if the Run() method does nothing than simply turn the "output" on when the // button is pressed). Read the definition of the lamp in reverse order: // - Incoming is simply the boolean signal of the button. // - This is made blink (BlinkedWhenTrue). // - This, still boolean, value gets mapped to the double number 0.0 for false and 1.0 for true // (MappedFromBoolean). // - This signal, which switches between 0.0 and 1.0, is then smoothed to slowly enlight or dimm the lamp // (Smoothed). // - This, finally, is fed into the AnalogPwmOutput controlling the LED. // So, using the fluent API for outputs is coded from back to front: Define the target output (here, the // PWM-controlled LED, that is an IDoubleOutput), and apply transformations until you get an "I(type)Output" // output where "(type)" matches the output type expected (here, an IBooleanOutput). AbstractIO.Samples.Sample03ButtonControlsLampPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue) .Smoothed(valueChangePerSecond: 1.0f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample04ButtonControlsLampEventBased // Sample 04: Control a lamp using a button, but this time do not poll the status of the button, but react // to the ValueChanged event (that is, reacting on an IRQ generated by the µC whenever the status of the // button's input pin changed). AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample04ButtonControlsLampEventBasedInvertingButton // Sample 04 again: Control a lamp using a button using events, but with an inverted button using the // ObserverableBooleanInputInverter class, coded using the fluent API that the extension methods offer. AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(DigitalInputPin.OnboardButton).Invert(), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample04ButtonControlsLampEventBasedSmoothly // Sample 04 again, but let the LED blink smoothly just as in Sample03ButtonControlsLampBlinkingSmoothly. // We do the very same here: Convert the IBooleanOutput of the event based method to the smoothly blinking // IDoubleOutput for the PWM-controlled LED. It works all the same whether we use a polling IBooleanInput // or the IRQ/event-based variant IObservableBooleanInput for the button. The output possibillities are just // the same. AbstractIO.Samples.Sample04ButtonControlsLampEventBased.Run( button: new Netduino3.ObservableDigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue) .Smoothed(valueChangePerSecond: 1.0f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0.0f, trueValue: 1.0f) .BlinkedWhenTrue(onDurationMs: 300, offDurationMs: 500)); #elif Sample05ControlLampBrightnessThroughAnalogInput // Sample 05: Let a LED light up just as bright (in the range from 0.0 to 1.0) as an analog input gives // values (also in the range from 0.0 to 1.0). Note that the input range is not scaled in any way in this // sample, but just goes straigt to the output. To run this sample, connect a variable resistor (such as a // photo cell) between anlog input pin A0 and GND (0V). Then, the lamp will light darker as more light goes // to the photo cell. AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample05ControlLampBrightnessThroughAnalogInputScaled // Sample 05 again, but this time auto-learn the actual incoming value range of the input and scale it to // the range from 0.0 to 1.0 using the ScaleToRangeInput class, coded using the fluent API of the // corresponding extension methods. This will cause the full range from 0.0 to 1.0 being used on the lamp, // regardless if, for example, the incoming values range only from 0.3 to 0.6. To run this sample, connect a // variable resistor (such as a photo cell) between anlog input pin A0 and GND (0V). AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0) .ScaleToRange(smallestValueMappedTo: 0.0f, largestValueMappedTo: 1.0f), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample05ControlLampBrightnessThroughAnalogInputScaledInverted // Sample 05 again, but this time the auto-learned ranged has swapped lower and upper limits. This results // in the lamp going brighter when the analog input signal gets lower (that is, the photo cell getting more // light, and vice versa. To run this sample, connect a variable resistor (such as a photo cell) between // anlog input pin A0 and GND (0V). AbstractIO.Samples.Sample05ControlLampBrightnessThroughAnalogInput.Run( input: new Netduino3.AnalogAdcInput(Netduino3.AnalogInputPin.A0) .ScaleToRange(smallestValueMappedTo: 1.0f, largestValueMappedTo: 0.0f), lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue)); #elif Sample06WaitForButtonPolling // Sample 06: Wait for an input to reach a specific value, or to change, using the WaitFor() and // WaitForChange() extension methods. In this sample, the button is used only as an IBooleanInput, so that // waiting will cause polling. See sample 07 for the exact same code, just using the butten as an // IObservableBooleanInput, working without polling. AbstractIO.Samples.Sample06WaitForButtonPolling.Run( button: new Netduino3.DigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample07WaitForButtonEventBased // Sample 07: Nearly the same as sample 06, but using the button as an IObservableBooleanInput insted of // a plain IBooleanInput. This allows the WaitFor() and WaitForChange() methods to use IRQ events instead of // polling: AbstractIO.Samples.Sample07WaitForButtonEventBased.Run( button: new Netduino3.ObservableDigitalInput(Netduino3.DigitalInputPin.OnboardButton), lamp: new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.OnboardLedBlue)); #elif Sample02LetMotorRun // Connect to the Adafruit V2 shield at its default address: shield = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(); // Use the sample controlling a lamp just control a motor, as both implement IDoubleOutput: AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: shield.GetDcMotor(1)); #elif Sample08LetManyMotorsRun // Control as many motors you whish on as many motor shields you whish simultaneously: // Let a lamp blink smoothly on a separate thread as a means to see how smooth all these operations can be // handled by the board: Thread blinkThread = new Thread( () => AbstractIO.Samples.Sample02SmoothBlinker.Run( lamp: new Netduino3.AnalogPwmOutput(Netduino3.DigitalPwmOutputPin.OnboardLedBlue))); blinkThread.Start(); // Run the sample, using as many motors as you like: // As additional ideas, suppose that: // - All motors can run on 9V, but one only on 6V. So we scale this motor's output by 6/9. // - One DC motor has its pins swapped and needs output in reverse polarity. So scale by a factor of -1. // Note that the Run() method does not know nor needs to know about this facts about the actual motors, and // that all we need to do is to pass scaled outputs using the fluent API to the Run() method. // // We pass 3 onboard LEDs to display the number of motors which are (still) accelerating or decelerating // as numbers 0, 1, 2 or greater than 2. // // We let the Run() method run on its own thread because blocking the main thread by waiting for // ManualResetEvents (as is done while the Run() method waits) would block the whole OS (as of 2018-05-05). var shield1 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(96); var shield2 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); var shield3 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(98); var shield4 = new AbstractIO.AdafruitMotorShieldV2.AdafruitMotorShieldV2(99); Thread runner = new Thread(() => AbstractIO.Samples.Sample08SmoothManyAnalogOutputs.Run( new IBooleanOutput[] { new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort1Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort2Led), new Netduino3.DigitalOutput(Netduino3.DigitalOutputPin.GoPort3Led) }, shield1.GetDcMotor(1), shield1.GetDcMotor(2), shield1.GetDcMotor(3), shield1.GetDcMotor(4), shield2.GetDcMotor(1), shield2.GetDcMotor(2), shield2.GetDcMotor(3), shield2.GetDcMotor(4), shield3.GetDcMotor(1).Scaled(factor: 6.0f / 9.0f), shield3.GetDcMotor(2), shield3.GetDcMotor(3), shield3.GetDcMotor(4), shield4.GetDcMotor(1).Scaled(factor: -1.0f), shield4.GetDcMotor(2), shield4.GetDcMotor(3), shield4.GetDcMotor(4))); runner.Start(); for (; ;) { Thread.Sleep(10); } #elif Sample09SimpleStepperMotor // Let a stepper motor turn randomly: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(); //new Thread(() => // AbstractIO.Samples.Sample09SimpleStepperMotor.Run(shield.GetStepperMotor(1, 2, 8))) // .Start(); const float scale = 0.4f; new Thread(() => AbstractIO.Samples.Sample09SimpleStepperMotor.Run( new StepperMotor(shield.GetDcMotor(1).Scaled(scale), shield.GetDcMotor(2).Scaled(scale), 8))) .Start(); for (; ;) { Thread.Sleep(10); } #elif Sample10StepperMotorClock // Let a simple clock run by turning a stepper motor a given number of steps every minute: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); const float clockScale = 0.2f; new Thread(() => AbstractIO.Samples.Sample10StepperMotorClock.Run( stepper: new StepperMotor(phase1Output: shield.GetDcMotor(1).Scaled(clockScale), phase2Output: shield.GetDcMotor(2).Scaled(clockScale), stepsPerStepCycle: 4), stepsPerMinute: 4, pauseBetweenStepsInMs: 50)) .Start(); for (; ;) { Thread.Sleep(10); } #elif Sample11SimpleTrainWithDoors // Let a train run: shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(97); AbstractIO.Samples.Sample11SimpleTrainWithDoors.Run( trainMotor: shield.GetDcMotor(1).Smoothed(valueChangePerSecond: 2.0f, rampIntervalMs: 20), trainReachedBottomStation: new BooleanOrInput(new Netduino3.DigitalInput(DigitalInputPin.D0), new Netduino3.DigitalInput(DigitalInputPin.D1)), doorMotor: shield.GetDcMotor(2), waitForDoorsToMoveInMs: 1000, waitWithOpenDoorsInMs: 3000, waitAroundDoorOperationsInMs: 1000); #elif Sample12ClockWithContinuouslyControlledMotor // Let a clock run that is driven by a simple DC motor (no stepper) and which has a digital input that gives // a specific number of "1" pulses for a turn of a specific axis of the clock's gear. // The motor is a simple DC motor. As its pins are swapped in the fischertechnik model currently, we use // the .Scaled() extension to turn its direction by a factor of -1. // The pulse switch is a contact customly built out of fischertechnik parts directly on a very small // metallic worm gear. Note that its value is not only fed into the model code, but also tee-like output to // a monitor LED. // The seconds lamp is driven independently of all this. The model code just has a timer changing a boolean // output each time it fires. To have the effect of a lamp going smoothly on and of, we use the // .Smoothed() extension method to smooth the boolean value from the timer code into a nice looking LED // pattern. // The ideal seconds per pulse are calculated for a miniaturized fischertechnik clock with the following // gear: // Motor worm => Z14 and worm => Z14 and worm (here pulses are detected) => Z14 and worm => Z22 and minutes. // So the relation of pulse detection to minutes is 1/14/22 and thus the turnaround time of the detecting // worm is 3600 s / 14 / 22 ≈ 11,69 seconds (rounded). var shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(); // Let a lamp blink in one-second-intervals: // Start a blinking seconds lamp calmly going on in one second and off again in the next: var secondsLamp = new Netduino3.AnalogPwmOutput(DigitalPwmOutputPin.OnboardLedBlue) .Scaled(quadraticCoefficient: 1f, factor: 0f, offset: 0f) .Smoothed(valueChangePerSecond: 1f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0f, trueValue: 1f); var secondsTimer = new System.Threading.Timer( (state) => { secondsLamp.Value = !secondsLamp.Value; }, null, 0, 1000); // Run the clock: AbstractIO.Samples.Sample12ClockWithContinuouslyControlledMotor.Run( motor: shield.GetDcMotor(3) .Scaled(factor: -1f), // If pins are reversed in the model, negate speed. minimumMotorSpeed: 0.08f, initialSpeedGuess: 0.11f, pulse: (new Netduino3.DigitalInput(DigitalInputPin.D2)) .MonitoredTo(teeTarget: new Netduino3.DigitalOutput(DigitalOutputPin.GoPort3Led)), idealSecondsPerCycle: 3600f / (22f * 14f), runAtFullSpeedSwitch: new DigitalInput(DigitalInputPin.OnboardButton)); #elif Sample13SimplifiedDevelopment // The most primitive program ever: Let a motor run when a button is pressed. shield = new AdafruitMotorShieldV2.AdafruitMotorShieldV2(address: 97); //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.DigitalInput(DigitalInputPin.D2), // Monitor a digital input pin // motor: shield.GetDcMotor(1) // Create a motor output // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // Map a boolean to a float // ); // Let the motor turn on and off smoothly! //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.DigitalInput(DigitalInputPin.D2), // motor: shield.GetDcMotor(1) // .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) // Smooth the float value // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // ); // Let a lamp monitor when the motor is on or off: //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.DigitalInput(DigitalInputPin.D2), // motor: shield.GetDcMotor(1) // .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .Distributed( // Distribute output to another one // shield.GetDcMotor(2) // A lamp output // .MappedFromBoolean(falseValue: 0f, trueValue: 1f)) // Mapped from boolean // ); // Let the lamp blink instead of only light up: //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.DigitalInput(DigitalInputPin.D2), // motor: shield.GetDcMotor(1) // .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .Distributed( // shield.GetDcMotor(2) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .BlinkedWhenTrue(onDurationMs: 500, offDurationMs: 500)) // Blink as long as pressed // ); // Let the lamp blink smoothly: //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.DigitalInput(DigitalInputPin.D2), // motor: shield.GetDcMotor(1) // .Smoothed(valueChangePerSecond: 0.5f, rampIntervalMs: 20) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .Distributed( // shield.GetDcMotor(2) // .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) // Smooth the blinking lamp // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .BlinkedWhenTrue(onDurationMs: 500, offDurationMs: 500)) //); // Replace the lamp with an analog photocell, auto-learning its value range: //AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( // button: new Netduino3.AnalogAdcInput(AnalogInputPin.A1) // An analog input // .ScaleToRange(smallestValueMappedTo: 0f, largestValueMappedTo: 1f) // auto-learning its range // .SchmittTrigger(threshold: 0.5f, hysteresis: 0.05f), // converted too boolean // motor: shield.GetDcMotor(1) // .Smoothed(valueChangePerSecond: 0.5f, rampIntervalMs: 20) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .Distributed( // shield.GetDcMotor(2) // .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) // .MappedFromBoolean(falseValue: 0f, trueValue: 1f) // .BlinkedWhenTrue(onDurationMs: 500, offDurationMs: 500)) // ); // Invert the behavior of the light barrier: AbstractIO.Samples.Sample13SimplifiedDevelopment.Run( button: new Netduino3.AnalogAdcInput(AnalogInputPin.A1) .ScaleToRange(smallestValueMappedTo: 0f, largestValueMappedTo: 1f) .SchmittTrigger(threshold: 0.5f, hysteresis: 0.05f) .Invert(), // Invert the light barrier motor: shield.GetDcMotor(1) .Smoothed(valueChangePerSecond: 0.5f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0f, trueValue: 1f) .Distributed( shield.GetDcMotor(2) .Smoothed(valueChangePerSecond: 2f, rampIntervalMs: 20) .MappedFromBoolean(falseValue: 0f, trueValue: 1f) .BlinkedWhenTrue(onDurationMs: 500, offDurationMs: 500)) ); // Run forever: Thread.Sleep(Timeout.Infinite); #else //#error Please uncomment exactly one of the samples. var startTime = DateTime.UtcNow; int periods = 0; var timer = new Timer( (state) => { periods++; double s = DateTime.UtcNow.Subtract(startTime).TotalSeconds; double p = periods; Debug.WriteLine(p.ToString() + " | " + s.ToString() + " | " + ((p - s) / s).ToString()); }, null, 1000, 1000); System.Threading.Thread.Sleep(Timeout.Infinite); #endif }