mBlock scratch need "map" function with one block


#1

Sometimes I use mBlock scratch with Arduino Uno and I need to map the sensor value into another values. So, why don’t you make the block for a map? Such as, map 0~1023 values into 100~500.
Of course 100~500 is the part of user’s input.


#2

Yes, I would like to see this type of function, too. I created the “Theremin” program from “A Gentle Introduction to Robotics” by Charles McKnight. It uses the ultrasonic sensors to measure the distance to an object and then play a sound, based on an index of distance increments. What this means is that it can only play 8 notes (or how many increments you set up), but I would like to directly translate the distances read from the sensors into a number that can be used to set the frequency of the tone generator. By being able to map distances directly to frequencies, you’d be able to create a true Theremin sound, which would essentially create a continuous “analog” up or down sound, instead of a series of discrete tone increments.


#3

The issue is that the mBlock code generator does not support generating any sort of data structures, not even a string (which I could coerce into being a single dimension array). That was a major pain when I was designing the maze solver. :frowning:


#4

So true!

What’s interesting is that this hits at problems within both mBlock and Scratch.

For mBlock, the key problem is that there’s no good user-facing tool to use existing Arduino functions. I have a gauge memory that this existed in some earlier version, but it’s certainly walled off now. Map is such a clean, canonical example of this need. Maybe map() is “too confusing” to have as a default block. Would it go in the Robots/Arduino section, even though it has nothing to do with the physical hardware? Would it go in Operators, even though it doesn’t function unless you’re uploading code to an Arduino? I can understand that map() represents a UI hazard.

We could avoid all of this is mBlock provided advanced users ability to create a Scratch block that called a particular Arduino function. Snap! does this for generic Javascript functions. if mBlock allowed this ability, then I could create a template program that has block calls for particular Arduino functions or libraries appropriate for a given project and then distribute those files to students.

The other limitation comes from Scratch. What I’ve down in the past is just built a Scratch block for map.

Obviously, this block would be better as a Reporter and not as a command. Creating a Scratch variable map_Output is a terrible kludge, and prevents us from using this in the flow of a program the way you would actual map(). Instead you have an extra level and extra variable floating around, like this.

Snap! allows user-created blocks to be Commands, Predicates or Reporters. Although doing this precise example in Snap! is confusing, since they use “map” in functional programing context of "apply this rule consistently across this set"sense.



Since that aspect of Scratch is unlikely to change, I can only hope that mBlock will shift their policy and allow easier access to the default tools already available in Arduino.

–andrew


#5

I’d proposed that mBlock be ported to Snap! (actually S4A) last year, but apparently it’s not a priority for Makeblock. That’s fine by the way, but I haven’t had time to do the port myself. I’d spoken to folks on the S4A site and there is interest, but someone has to do the heavy lifting to get it started and I’m sort of booked through next summer with other projects. :frowning:

The really awesome part about Snap!/S4A is that they are in HTML/CSS/Javascript and don’t rely on a proprietary 3rd party runtime (Adobe Air). Oh, and then there’s the first class data structures, variables and methods…


#6

You should be able to use tethered makeblock boards in Snap, since the basic mBot firmware is still based on firmata.

Sadly, as Makeblock scatters their energy and attention to the wind chasing cones and littleBits and increasingly specialized iOS apps, I don’t have any hope for sustained action or improvement of mBlock in the next few years.


#7

I posed that question to the Makeblock team and was informed that their firmata is a bit different. However, I was unable to get any particulars as to what the differences were.


#8

I ran a diff on the make block firmata pulled from github ( https://github.com/Makeblock-official/mBot_Firmata ) and the standard Firmata pulled from my Arduino IDE.

It’s also notable Makeblock forked from standard firmata in 2015, so there may be changes between the two that reflect updates to standard firmata, rather than additions from makeblock. Reading through both files, it looks like the biggest change in standard firmata was a slight rewrite of how Firmata handles I2C timing and communication.

The last listed update in the comments was from Riven in April of 2015.

Many of the changes are obvious. Most sections have some variation on this:

#include <Servo.h>
#include <Wire.h>
#include <Firmata.h>
// makeblock defined libs
#include "MeBuzzer.h"
#include "MeIR.h"`

// mbot hardware specified command
#define RGBLED_SET            0x11 // set rgbled color
#define SONAR_GET            0x12 // read sonar distance
#define LIGHTSENSOR_GET      0x13
#define BUZZER_TONE          0x14
#define INFRA_READ           0x15

There’s also a large section that appears to be related to the RGB LED strips. Which makes sense, because those require some specific timing and generally use larger libraries.

/** ws2812 related **/
#define NOP __asm__("nop\n\t")
#define w_nop1  __asm__("nop      \n\t")
#define w_nop2  __asm__("rjmp .+0 \n\t")
#define HIGH0 *P_RGB = PINON;NOP;NOP;*P_RGB = PINOFF;
#define HIGH1 *P_RGB = PINON;NOP;NOP;NOP;NOP;NOP;NOP;*P_RGB = PINOFF;
uint8_t bytes[6];
void setREGBLED(uint8_t pix, uint8_t r, uint8_t g, uint8_t b){
  volatile uint8_t *P_RGB; // port register of ws2812
  uint8_t B_RGB;  // register mask of ws2812 output pin
  uint8_t PINON,PINOFF;
  char a;
  char i,j,k;
  uint8_t pin=13;
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
  P_RGB = portOutputRegister(digitalPinToPort(pin));
  B_RGB = digitalPinToBitMask(pin);
  PINON = *P_RGB | B_RGB;
  PINOFF = *P_RGB & ~B_RGB;
  
  if(pix==0){
    bytes[0] = bytes[3] = g;
    bytes[1] = bytes[4] = r;
    bytes[2] = bytes[5] = b;
  }else{
    bytes[(pix-1)*3] = g;
    bytes[(pix-1)*3+1] = r;
    bytes[(pix-1)*3+2] = b;
  }
  
  cli();
  for(i=0;i<6;i++){ // the max pixel length 16
    // send 24bit rgb color
      a = bytes[i];
      for(k=0;k<8;k++){
        if(a&0x80){
          HIGH1;
        }else{
          HIGH0;
        }
        a<<=1;
      }
  }
  sei();
  digitalWrite(pin, LOW);
}

Lower down, another addition of dedicated mBot HW features. RGB LEDs, Buzzers, Sonar.

    case RGBLED_SET:
      setREGBLED(argv[0],argv[1],argv[2],argv[3]);
      break;
    case SONAR_GET:
      {
        uint8_t pin;
        uint32_t duration;
        pin = argv[0];
        digitalWrite(pin,LOW);
        delayMicroseconds(2);
        digitalWrite(pin,HIGH);
        delayMicroseconds(10);
        digitalWrite(pin,LOW);
        pinMode(pin,INPUT);
        duration = pulseIn(pin,HIGH,10000);
        Firmata.write(START_SYSEX);
        Firmata.write(SONAR_GET);
        Firmata.write((duration>>24)&0xff);
        Firmata.write((duration>>16)&0xff);
        Firmata.write((duration>>8)&0xff);
        Firmata.write(duration&0xff);
        Firmata.write(END_SYSEX);
      }
      break;
    case LIGHTSENSOR_GET:
      {
        int analog = analogRead(A6);
        Firmata.write(START_SYSEX);
        Firmata.write(LIGHTSENSOR_GET);
        Firmata.write((analog<<8)&0xff);
        Firmata.write((analog)&0xff);
        Firmata.write(END_SYSEX);
      }
      break;
    case BUZZER_TONE:
      {
        buzz.tone((int)argv[0]*10, (int)argv[1]*10);
      }
      break;
  }

Finally, a section for reading from the IR port to allow remote control.

 // ir read
  if(ir.decode()){
    unsigned char irRead = ((ir.value>>8)>>8)&0xff;
    Firmata.write(START_SYSEX);
    Firmata.write(INFRA_READ);
    Firmata.write(irRead);
    Firmata.write(END_SYSEX);  
  }

Aside from changes between the two docs that relate to the newer Standard Firmata changing some naming conventions, there’s also a strand in Standard Firmata about serial communication that doesn’t show up in the mBot version.

–andrew