esp32blockly/public/hbridgemotor-addon.js

168 lines
5.2 KiB
JavaScript

// h-bridge Motor Driver addon
//
// Adds a "h-bridge Motor" toolbox category with:
// - motor_init: set up a motor with IN1 and IN2 pins
// - motor_speed: set speed from -255 (full reverse) to +255 (full forward)
// - motor_stop: stop a motor
//
// Generates device-appropriate MicroPython:
// - ESP32 / RP2040: machine.Pin + machine.PWM
// - micro:bit: pinN.write_analog()
// --- Block definitions ---
api.Blockly.Blocks['hbridge_motor_init'] = {
init() {
this.appendDummyInput()
.appendField('init motor')
.appendField(new api.Blockly.FieldDropdown([
['A', 'A'],
['B', 'B'],
]), 'MOTOR')
.appendField('IN1 pin')
.appendField(new api.Blockly.FieldNumber(2, 0, 48, 1), 'IN1')
.appendField('IN2 pin')
.appendField(new api.Blockly.FieldNumber(3, 0, 48, 1), 'IN2');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(30);
this.setTooltip('Initialize an h-bridge motor channel with two pins');
},
};
api.Blockly.Blocks['hbridge_motor_speed'] = {
init() {
this.appendDummyInput()
.appendField('set motor')
.appendField(new api.Blockly.FieldDropdown([
['A', 'A'],
['B', 'B'],
]), 'MOTOR');
this.appendValueInput('SPEED')
.setCheck('Number')
.appendField('speed');
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(30);
this.setTooltip('Set motor speed: -255 (full reverse) to +255 (full forward)');
},
};
api.Blockly.Blocks['hbridge_motor_stop'] = {
init() {
this.appendDummyInput()
.appendField('stop motor')
.appendField(new api.Blockly.FieldDropdown([
['A', 'A'],
['B', 'B'],
]), 'MOTOR');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setColour(30);
this.setTooltip('Stop an h-bridge motor (brake)');
},
};
// --- Helpers used by generators ---
function isMicrobit() {
return api.getDeviceId() === 'microbit';
}
function mbPin(pin) {
var n = Math.max(0, Math.min(20, parseInt(pin, 10) || 0));
return 'pin' + n;
}
// --- Code generators ---
api.pythonGenerator.forBlock['hbridge_motor_init'] = function (block) {
var motor = block.getFieldValue('MOTOR');
var in1 = block.getFieldValue('IN1');
var in2 = block.getFieldValue('IN2');
var m = motor.toLowerCase();
if (isMicrobit()) {
// micro:bit: no explicit init needed, just store pin numbers for later use.
// We define variables so speed/stop blocks can reference them.
api.pythonGenerator.definitions_['import_microbit'] = 'from microbit import *';
api.pythonGenerator.definitions_['hb_motor_' + m + '_pins'] =
'motor_' + m + '_in1 = ' + mbPin(in1) + '\n' +
'motor_' + m + '_in2 = ' + mbPin(in2);
api.pythonGenerator.definitions_['hb_set_motor_mb'] = [
'def _hb_set_motor(p1, p2, speed):',
' speed = max(-255, min(255, int(speed)))',
' duty = abs(speed) * 4',
' if speed > 0:',
' p1.write_analog(duty)',
' p2.write_analog(0)',
' elif speed < 0:',
' p1.write_analog(0)',
' p2.write_analog(duty)',
' else:',
' p1.write_analog(0)',
' p2.write_analog(0)',
].join('\n');
} else {
// ESP32 / RP2040: machine.PWM
api.pythonGenerator.definitions_['import_machine'] =
'from machine import Pin, PWM';
api.pythonGenerator.definitions_['hb_motor_' + m + '_in1'] =
'motor_' + m + '_in1 = PWM(Pin(' + in1 + '), freq=1000, duty=0)';
api.pythonGenerator.definitions_['hb_motor_' + m + '_in2'] =
'motor_' + m + '_in2 = PWM(Pin(' + in2 + '), freq=1000, duty=0)';
api.pythonGenerator.definitions_['hb_set_motor'] = [
'def _hb_set_motor(pwm1, pwm2, speed):',
' speed = max(-255, min(255, int(speed)))',
' duty = abs(speed) * 4',
' if speed > 0:',
' pwm1.duty(duty)',
' pwm2.duty(0)',
' elif speed < 0:',
' pwm1.duty(0)',
' pwm2.duty(duty)',
' else:',
' pwm1.duty(0)',
' pwm2.duty(0)',
].join('\n');
}
return '';
};
api.pythonGenerator.forBlock['hbridge_motor_speed'] = function (block) {
var motor = block.getFieldValue('MOTOR');
var m = motor.toLowerCase();
var speed = api.pythonGenerator.valueToCode(
block, 'SPEED', api.pythonGenerator.ORDER_NONE
) || '0';
return '_hb_set_motor(motor_' + m + '_in1, motor_' + m + '_in2, ' + speed + ')\n';
};
api.pythonGenerator.forBlock['hbridge_motor_stop'] = function (block) {
var motor = block.getFieldValue('MOTOR');
var m = motor.toLowerCase();
return '_hb_set_motor(motor_' + m + '_in1, motor_' + m + '_in2, 0)\n';
};
// --- Register toolbox category ---
api.registerCategories([
{
kind: 'category',
name: 'H-Bridge Motor',
colour: '30',
contents: [
{ kind: 'block', type: 'hbridge_motor_init' },
{
kind: 'block',
type: 'hbridge_motor_speed',
inputs: {
SPEED: { shadow: { type: 'math_number', fields: { NUM: 200 } } },
},
},
{ kind: 'block', type: 'hbridge_motor_stop' },
],
},
]);