Ml5: hands object in draw() is undefined

I’m trying to incorporate a model to detect hands in the camera provided by ml5 into my work (a similar example is available here).
The modelLoaded function is properly called, but I’m getting the error that ‘hands’ within draw() is not defined and its length can’t be read. I’m suspecting it’s probably because of the asynchronous part of JavaScript because I’m mostly trying out the example above. Does anybody know how to fix the issue?

Thank you so much in advance.

TypeError: Cannot read property ‘length’ of the undefined ‘hands’

let capture; 
let state;

//handpose 
let handpose;
let hands;

function preload() {
  handpose = ml5.handpose(capture, modelLoaded);
}

function setup() {
  createCanvas(400, 300); 
  capture = createCapture(VIDEO);
  capture.size(width,height);
  capture.hide();

}

function modelLoaded() {
  console.log('Model Loaded!');
  // Listen to new 'pose' events
  handpose.on('pose', gotPose);
}

function gotPose(results) {
  hands = results;
}

function draw(){
  if (state == 0) {
     drawIntro();
  }else if (state == 1) {
    ...
  } else if (state == 2) {
    ...
    drawPlaying();
  }
}

function drawPlaying() {
  for (var i = 0; i < 9; i++) {
    
    if (hands.length > 1 && i <= 3) { //throwing off the error
      let hand = hands[0];
    }else if (hands.length > 1 && i > 4) {
      let hand = hands[1];
    }else{
      let hand = hands[0];
    }
 }

...

}

Yes without the full code I cannot test it but I think your guess is right. I would wrap the whole drawPlaying() function with

if (hands !== undefined) {
   ...
}

to see if that will skip the drawing until the model is loaded and hand coordinates are returned.

@micuat Thank you for your suggestion! I tried your example, but I think the problem is that hands are not detected in the first place even though the model seems already loaded…

Now my code is error-free, but since hands are not detected, nothing interesting is happening. Drawing should be happening inside drawHands() called inside draw(). But the event listener handpose.on() is never called even though I show my hand to the camera. So there is no value in the ‘hands’, which makes nothing really happen.

//camera
let capture; 
let selected;
let img;

//handpose 
let handpose;
let hands;
let landmarks = [[0,0,0],[0,0,0],[0,0,0],[0,0,0]];

function preload() {
  handpose = ml5.handpose(capture, modelLoaded);
  
}

function setup() {
  //textFont(myFont);

  createCanvas(400, 300); 
  //noLoop();
  frameRate(3);

  //capture.loadPixels();
  capture = createCapture(VIDEO);
  capture.size(width,height);
  capture.hide();

  //newPixel = createImage(capture.width, capture.height)
  selected = createImage(50, 50);

  angleOffsetA = radians(3);
  angleOffsetB = radians(7);

}

function draw() {
  ...

  if (hands !== undefined) {
    drawHands();
  }  

}

function modelLoaded() {
  console.log('Model Loaded!');
  // Listen to new 'pose' events
  handpose.on('pose', gotPose);
}

function gotPose(results) {
  hands = results;
  console.log('Hands detected')
  drawHands();
}

function drawHands() {

  if (hands.length > 1 && i <= 3) {
    let hand = hands[0];
  }else if (hands.length > 1 && i > 4) {
    let hand = hands[1];
  }else{
    let hand = hands[0];
  }

  let landmarks_test = hand.landmarks;
  colorMode(RGB);
  fill(255, 100);
  stroke(100);
  for (let i = 0; i < landmarks_test.length; i++) {
    let [x, y, z] = landmarks_test[i];
    // z is depth
    ellipse(x, y, 20);
  }

  landmarks = hand.landmarks.slice(4*i+5, 4*i+9);
  //let [x, y, z] = landmarks[i];
}

Yes I get what you mean. If you think it’s a problem specific to ml5.js, it might be better to ask them directly instead of this forum. You can reach out to them on their github or discord (and let us know if there is an update :slight_smile: )