// 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' }, ], }, ]);