我正在使用cylon.js编写一些带有node.js的电机控件。我有一个伺服,当你给它一个角度去有一个回调函数。当它完成该功能时,我想做另一个阅读,并给它一个新的角度,回调再做一次阅读......等等。
目前的代码是:
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), controlServo(servo, angleSensor));
}
这会让堆栈溢出四分之一秒。
答案 0 :(得分:3)
用Cylon.js做你想做的事是不可能的。 Cylon.js的内部“写入”操作“回调”不是异步的,并且在机械完成移动时不会被调用。它在写操作后立即被调用。 Cylon只能将角度值写入伺服系统,从而以最大速度机械地移动喇叭。如果它是一个慢速伺服,它可能需要2到0秒,从0到180度才能实际机械完成。与此同时,Cylon已经召回了回调。这样做的原因是因为没有办法以一种对所有伺服模型始终正确的方式来概括回调行为,而无需做一些额外的工作。
在Johnny-Five中,我们通过提供“完成时间”参数来实现速度控制。这是通过将距离与新角度分成步骤以在指定的“完成时间”内移动来完成的。该过程的副作用是Johnny-Five伺服实例可以知道移动是否机械完成,因为步骤较小且时间受到控制。因此,我们有一个“move:complete”事件,在任何定时移动完成时发出。
var servo = new five.Servo(9); servo.on("move:complete", function() { // we've arrived! }); // change takes 500ms to complete servo.to(180, 500);
可以很容易地与模拟传感器结合使用:
var servo = new five.Servo(9); var sensor = new five.Sensor({ pin: "A0", scale: [ 0, 180 ] }); servo.on("move:complete", function() { update(); }); function update() { // change takes 200ms to complete servo.to(sensor.value, 200); } update();
更简单:
var servo = new five.Servo(9); var sensor = new five.Sensor("A0"); sensor.scale(0, 180).on("change", function() { servo.to(this.value); });
答案 1 :(得分:2)
解决此问题的更好方法是使用timeout
而不是递归。这最终会在下一个tick上调用你的函数,它永远不会溢出。
function ControlServo(servo, angleSensor){
robo.servo.angle(angleSensor.Read(), function() {
setTimeout(function() { ControlServo(servo, angleSensor)}, 0);
});
};
您可以通过将timeout
移动到servo.angle
函数来缩短此时间,但您可能需要将其作为其他用途的回调。上面的方法不需要其他更改,因为回调只是设置超时。
另一个选项是setImmediate
,它似乎将函数调用放在当前tick的末尾,而不是下一个的开头。由于setTimeout
总会引起轻微延迟,setImmediate
可能会更快;但是,我不知道使用它可能会做出哪些其他权衡,因为我自己并没有使用它。