rwaldron / johnny-five

JavaScript Robotics and IoT programming framework, developed at Bocoup.
http://johnny-five.io
Other
13.26k stars 1.76k forks source link

Loop problem #1736

Open rodolphonetto opened 3 years ago

rodolphonetto commented 3 years ago

Hi guys I`m having problems to control the board.loop feature, my code is running asynchronous and I could not make it working adding awaits or something like that, it always run out of order, my console output for that code is that. Someone can help me to understand what should I do? thanks!!


Line 1 value: 0
Line 1 mode: 1
Line 1: 0
Line 1 mode: 1
Line 2: 1
Line 2 mode: 0
Line 2: 1
Line 2 mode: 0
-----------------------------------
Line 1 value: 0
Line 1 mode: 1
Line 1: 0
Line 1 mode: 1
Line 2: 1
Line 2 mode: 0
Line 2: 1
Line 2 mode: 0```

```  board.loop(1000, () => {
    console.log('-----------------------------------')
    board.pinMode(5, 0)
    board.pinMode(4, 1)
    linha1.query(function (state) {
      console.log('Line 1 value:', state.value)
      console.log('Line 1 mode:', state.mode)
    })
    linha2.query(function (state) {
      console.log('Line 2:', state.value)
      console.log('Line 2 mode:', state.mode)
    })
    board.pinMode(5, 0)
    board.pinMode(4, 1)
    board.digitalWrite(4, 0)
    linha1.query(function (state) {
      console.log('Line 1:', state.value)
      console.log('Line 1 mode:', state.mode)
    })
    linha2.query(function (state) {
      console.log('Line 2:', state.value)
      console.log('Line 2 mode:', state.mode)
    })
 })
})``` 
dtex commented 3 years ago

When we get a value back for a pin, it's going to run all the query callbacks without any regard to other pins.

There are some atypical things here that make me think this code was architected as though it were going to be written in Arduino C whereas it could be more simple

You have a digital input and a digital output. This might be a button and an LED. The "J5 way" to do this would be:

const five = require("johnny-five");

const board = new five.Board();

board.on("ready", function() {
  const button = new five.Button(5);
  const led = new five.Led(4);

  button.on("down", function() {
    led.on();
  });

   button.on("up", function() {
    led.off();
  });
});

Since the order of the callback execution is important to you, I suspect you are trying to do something more complicated. Can I ask what kind of hardware you are trying to control?

rodolphonetto commented 3 years ago

Hi, thanks for you help. I did this example before and all worked fine. The hardware I'm creating is a magnetic chessboard. I will use 64 reed switchs for it. For now I'm doing a 2x2 only for tests and I could make it work today using all kind of workarounds, of course the code is terrible but... works. There is other ideas to not use this callback hell and setTimeOuts I used? here goes the code

const five = require('johnny-five')

const board = new five.Board({ timeout: 3600 })

const a = [
  { casa: 1, status: false },
  { casa: 2, status: false },
]

const b = [
  { casa: 1, status: false },
  { casa: 2, status: false },
]

board.on('ready', function () {
  const colunaA = new five.Pin({
    pin: 2,
    type: 'digital',
    mode: 0,
  })
  const colunaB = new five.Pin({
    pin: 3,
    type: 'digital',
    mode: 0,
  })

  const linha1 = new five.Pin({
    pin: 4,
    type: 'digital',
    mode: 0,
  })

  const linha2 = new five.Pin({
    pin: 5,
    type: 'digital',
    mode: 0,
  })

  board.digitalWrite(2, 1)
  board.digitalWrite(3, 1)

  const managePins = (time, linha, i) => {
    board.wait(time, () => {
      linhas.forEach((linhaDesligar) => {
        if (linha !== linhaDesligar) {
          board.wait(time + 30, () => {
            board.pinMode(linhaDesligar, 0)
            board.wait(time + 60, () => {
              board.pinMode(linha, 1)
              board.digitalWrite(linha, 0)
              board.wait(time + 90, () => {
                colunaA.query(function (state) {
                  a[i].status = !state.value ? true : false
                })
                colunaB.query(function (state) {
                  b[i].status = !state.value ? true : false
                })
              })
            })
          })
        }
      })
    })
  }

  const linhas = [4, 5]

  let time = 0

  setInterval(() => {
    for (let i = 0; i < linhas.length; ++i) {
      ;(function (i) {
        setTimeout(function () {
          if (i === 0) {
            time = 0
          }
          managePins(time, linhas[i], i)
        }, 200 * (i + 1))
      })(i)
    }
    setTimeout(() => {
      console.log('a1', a[0].status ? 'Tem peça' : 'Não tem peça')
      console.log('a2', a[1].status ? 'Tem peça' : 'Não tem peça')
      console.log('b1', b[0].status ? 'Tem peça' : 'Não tem peça')
      console.log('b2', b[1].status ? 'Tem peça' : 'Não tem peça')
      console.log('----------------------------------------')
    }, 450);
  }, 1000)
})
dtex commented 3 years ago

There's a lot of ways to do this. I'd probably start with something like:

let inHand = {}, squares = {};
let board = new five.board();

class Square {
  #state = {};

  constructor(config = {})) {
    #state = config;
    this.switch = new five.Switch(config.pin);
    this.name = config.name;

    this.switch.on("close", () => {
      this.place();
    }

    this.switch.on("open", () => {
      this.lift();
    }
  }

  place() {
    if (inHand) {
      #state = {...inHand};
      #inHand = null;
      console.log(`The ${#state.color} ${#state.piece} is on square ${this.name}`);
    }
  }

  lift() {
    if (#state) {
      inHand = {...#state};
      #state = null;
      console.log(`The ${inHand.color} ${inHand.piece} is in hand`);
    }
  }

}

board.on("ready", function() {
  // An array of all the squares with their algebraic notation name, pin the reed switch is attached to, and their initial state
  [
    { color: "white", piece: "queen", name: "a1", pin: 0 }, 
    { name: "b1", pin: 1 },
    { color: "black", piece: "queen", name: "a2", pin: 2 }, 
    { name: "b2", pin: 3 }
  ].forEach(config => {
    squares[config.name] = new Square(config);
  })
});
rodolphonetto commented 3 years ago

Idk how to thank you for such an amazing answer!

I'm studing it and trying to understand. I have two questions

What does that # means? I`ve never seen this on JS

And I dont have a pin for each switch, I use only 8 pins for collumns and 8 for rows, then I cross then to see if is on or off

and again thank you for your help!!

dtex commented 3 years ago

# indicates a private instance field. It probably doesn't need to be private. I just used it out of habit.

then I cross then to see if is on or off

I see how that would work for one piece, but not more than one piece. I'd like to learn. Do you have a link that explains it?

Update: I found a link. I see you'll need to create a custom read loop, and I also understand now why you needed to change pin modes. Let me see if I can find where someone has done this before in J5.

rodolphonetto commented 3 years ago

I'm trying to do what is explained here: https://arduino.stackexchange.com/questions/31885/need-help-in-circuit-diagram-of-88-reed-switch-matrix

The response that has the arduino pic.

Since I'm noob with eletronics that was the best way I found out.

And again thank you so much for your help!! I'm into this problem for about 15 days, today I could solve it with that terrible soluction but of couse if we can go with a better approch would be good :D

dtex commented 3 years ago

Cool, that helps a lot. Some tips:

More difficult tips:

rodolphonetto commented 3 years ago

Thank you for all the help you gave me, I'll try to clean my code following this tips. I've tried to use async/await insted of callbacks but without sucess, for sure was some mistake I was making, I'll try it again, thank you!