Catching button press events


#1

As has been discussed, the When button [pressed] block doesn’t generate any code when used in an mBot Program collection. I’m trying to use the if <button [pressed]> conditional statement in its place, but this doesn’t seem very reliable. It would be very useful if the When button [pressed] event could be generated as the interrupt it’s intended to be, but I realize that may be difficult. Perhaps I’m missing something, so I’m posting the code below. Any comments, suggestions, gratefully accepted.


#2

Which button is the code block intended to define? I assume it’s an on-board button? Certainly not the reset button I would imagine.

I am curious as well.

It also seems ambiguous as to whether the ‘button pressed’ translates to a built-in variable with a boolean state.

Interesting usage in comparison to the IR remote, where we would get a hex value for the key pressed to compare rather than simply capturing a key press event to initiate the function.


#3

@chuckmcknight,

See the comments in the code. Yes, an interrupt would be very helpful in this and many other situations where user input is needed.

I think this code works better if you remove the 2s wait at the end of PlayMelody.

SoundAndLight2.sb2 (75.1 KB)

Hope this helps.

Mike


#4

Hi Mike,

I’ll give it a shot tomorrow to see what happens, and thanks!


#5

The following solution works for what I think you are trying to do, which is Multitasking.
The code below allows the robot to Line Follow for example and keep doing it while the robot is also checking to see if the on board button has been presses.

The nice thing here is that you can run multiple mBot Program starter blocks and both of these will run their programs simultaneously (in a multi-threaded manner)
Use a Variable to switch tasks as needed.
Use the Functions to create sub-programs to reduce the size of the controlling main program.

In this example the Main Program (wish I could name the starter blocks) initialises TaskNo to 0.
A Forever block loops through the optional tasks in turn executing only the one that is active, initially the Line Following function.
The Line Following function does not contain a Forever loop because you want the main program to control how the robot loops through the programs. It’s quick enough to have a line following program react as if it was the lone program.

Meanwhile the second mBot Program starter block is running a Forever Block that is constantly checking for the on-board button to be pressed.

The program will Line Follow indefinitely, unless the button is pressed.

When the button is pressed, the variable TaskNo is changed to a value of 1.

The Main program sees this change and Skips the first IF decision as its FALSE and goes on to check the second IF which is TRUE and executes the debug code stopping the motors and playing a tone, waiting 1 second and then sets the variable TaskNo back to zero (0) so that the robot will go back to Line Following.

I would prefer if a CaseWhere control structure was available in Scratch however this is not the case and we need to use IF decision controls.

Depending on your application IF ELSE may be more appropriate, however, use IF ELSE when you want the selection of tasks to be mutually exclusive. By using multiple IF’s as use here, each is always checked and can be executed at any time. If you use IF ELSE in this case the program may miss an event if the button is pressed between checking iterations, highly unlikely but possible.

Here is a more comprehensive example Multitasking using mBlock

Hope this helps.


#6

Hi @Tards57,

I did a variation of your program (see below), but the button presses aren’t getting caught any more reliably.

Looking at the Arduino code that is generated (see below), it’s not really multi-tasking, per se. It more like doing state machine programming where the instructions, in this case the if statements, are being executed sequentially.

#include <Arduino.h>
#include <Wire.h>
#include <Servo.h>
#include <SoftwareSerial.h>

#include <MeMCore.h>

double angle_rad = PI/180.0;
double angle_deg = 180.0/PI;
void PlayMelody();
double ProgramState;
MeBuzzer buzzer;
double MelodySwitch;
void toggleLEDs();
MeRGBLed rgbled_7(7, 7==7?2:4);

void PlayMelody()
{
    if((ProgramState) < (4)){
        buzzer.tone(131, 500);
        buzzer.tone(147, 500);
        buzzer.tone(165, 500);
    }else{
        buzzer.noTone();
    }
}

void toggleLEDs()
{
    if(((ProgramState)==(1))){
        rgbled_7.setColor(0,0,60,0);
        rgbled_7.show();
    }

    if(((ProgramState)==(2))){
        rgbled_7.setColor(0,0,60,60);
        rgbled_7.show();
    }

    if(((ProgramState)==(3))){
        rgbled_7.setColor(0,60,0,0);
        rgbled_7.show();
    }

    if(((ProgramState)==(4))){
        rgbled_7.setColor(0,0,0,0);
        rgbled_7.show();
    }
}

void setup()
{
    ProgramState = 1;
    pinMode(A7,INPUT); 
}

void loop()
{
    if(((ProgramState)==(1))){
        MelodySwitch = 1;
    }
    if(((ProgramState)==(2))){
        MelodySwitch = 1;
    }
    if(((ProgramState)==(3))){
        MelodySwitch = 1;
    }
    if(((ProgramState)==(4))){
        MelodySwitch = 0;
    }
    PlayMelody();
    toggleLEDs();
    if((0^(analogRead(A7)>10?0:1))){
        ProgramState += 1;
    }
    if((ProgramState) > (4)){
        ProgramState = 1;
    }
}

I think it is likely possible to simulate a kind of multi-tasking, but it requires the program to be written in the Arduino IDE, not Scratch/mBlock because you need to be able to access the interrupts. Also, it is important to understand that barring this approach, the mCore/Arduino Uno microprocessors are single-tasking and execute programs in a sequential fashion, regardless of the number of mBot program start blocks used.

An excellent exercise to understand this is to switch to Arduino mode (under the Edit menu) and watch what code gets generated. Arduino code has a single setup() method and a single loop() method. If you build your program in this mode, you will see that it really isn’t making multiple mBot programs, just stuffing everything in each of the forever() loops into the loop() method.

Best regards,

Chuck


#7

Hi @mddickey,

I tried your code, and while it was better at catching the button presses, it was not the solution I was hoping for. I’ll have to redo the app in pure Arduino code and use interrupts to catch the button presses.

Dang it. :wink:


#8

Is this the Interrupt you mention? Cool, I want to see how much you can actually use it for!
AttachInterrupt


#9

@Gort,

Yes, that is the one that will define the interrupt. At the bottom of that page you will see a link for the DetachInterrupt, which removes an interrupt. There are also a couple of functions NoInterrupts, which will turn off all interrupts, and Interrupts, which will turn them back on.

Mike