Add digital output block and GPIO handling
- Introduced a new Blockly block for setting digital output pins (`digitalOut`). - Implemented the corresponding handler in Python to manage digital output actions. - Updated dummy, GPIO, and real hardware interfaces to support digital output functionality. - Modified the workspace configuration to include the new digital output block in the Blockly environment. - Added potential enhancements to the README for future improvements.master
parent
c82e30b9b1
commit
dced16a00b
986
DOCUMENTATION.md
986
DOCUMENTATION.md
File diff suppressed because it is too large
Load Diff
|
|
@ -18,6 +18,8 @@ Feature Task : Penjabaran Pekerjaan yang ready untuk dikerjakan. Ta
|
|||
|
||||
# Potential Enhancements
|
||||
this list is short by priority
|
||||
- **Potensial inefective development**: in handlers/hardware use interface.py to all hardware (dummy, ros2, and hardware) class that posibly haavily change.
|
||||
- ** UI bug **: stop button not actualy stop execution. tried with long delay with loop and press stop button, program still continue
|
||||
- **Launch files**: `blockly_bringup` package with ROS2 launch files to start all nodes with one command
|
||||
- **Sensor integration**: Subscriber nodes for sensor data feeding back into Blockly visual feedback
|
||||
- **RealHardware implementation**: Fill in ROS2 publishers/service clients for actual Pi hardware nodes (topics TBD)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
BlockRegistry.register({
|
||||
name: 'digitalOut', // Must match Python handler name
|
||||
category: 'Robot',
|
||||
categoryColor: '#5b80a5',
|
||||
color: '#4CAF50',
|
||||
tooltip: 'set a digital output pin to HIGH (turn on LED)',
|
||||
|
||||
definition: {
|
||||
init: function () {
|
||||
this.appendValueInput('digitalOut')
|
||||
.appendField(' gpio:')
|
||||
// FieldNumber(default, min, max, step)
|
||||
.appendField(new Blockly.FieldNumbint(er(1, 0, 27, 1), 'GPIO')
|
||||
.setCheck('Boolean')
|
||||
.appendField(' state:');
|
||||
|
||||
this.setPreviousStatement(true, null); // connect above
|
||||
this.setNextStatement(true, null); // connect below
|
||||
this.setColour('#4CAF50');
|
||||
this.setTooltip('set a digital output pin to HIGH (turn on LED)');
|
||||
}
|
||||
},
|
||||
|
||||
generator: function (block) {
|
||||
const GPIO = block.getFieldValue('GPIO');
|
||||
const STATE = Blockly.JavaScript.valueToCode(block, 'digitalOut', Blockly.JavaScript.ORDER_ATOMIC) || 'false';
|
||||
return (
|
||||
'highlightBlock(\'' + block.id + '\');\n' +
|
||||
'await executeAction(\'digital_out\', { gpio: \'' + GPIO + '\', state: \'' + STATE + '\' });\n'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const BLOCK_FILES = [
|
||||
'led_on.js',
|
||||
'led_off.js',
|
||||
'digitalOut.js',
|
||||
'delay.js',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -15,3 +15,11 @@ def handle_led_off(params: dict[str, str], hardware) -> tuple[bool, str]:
|
|||
pin = int(params["pin"])
|
||||
hardware.set_led(pin, False)
|
||||
return (True, f"LED on pin {pin} turned OFF")
|
||||
|
||||
@handler("digital_out")
|
||||
def handle_digital_out(params: dict[str, str], hardware) -> tuple[bool, str]:
|
||||
gpio = int(params["gpio"])
|
||||
state = bool(params["state"])
|
||||
hardware.set_digital_out(gpio, state)
|
||||
state_str = "HIGH" if state else "LOW"
|
||||
return (True, f"GPIO pin {gpio} set to {state_str}")
|
||||
|
|
@ -22,3 +22,6 @@ class DummyHardware(HardwareInterface):
|
|||
def is_ready(self) -> bool:
|
||||
self.call_log.append("is_ready()")
|
||||
return True
|
||||
|
||||
def set_digital_out(self, gpio: int, state: bool) -> None:
|
||||
self.call_log.append(f"set_digital_out(gpio={gpio}, state={state})")
|
||||
|
|
|
|||
|
|
@ -30,3 +30,9 @@ class GpioHardware(HardwareInterface):
|
|||
|
||||
def is_ready(self) -> bool:
|
||||
return self._initialized
|
||||
|
||||
def set_digital_out(self, gpio: int, state: bool) -> None:
|
||||
if not self._initialized:
|
||||
raise RuntimeError("GPIO not available on this platform")
|
||||
self._gpio.setup(gpio, self._gpio.OUT)
|
||||
self._gpio.output(gpio, self._gpio.HIGH if state else self._gpio.LOW)
|
||||
|
|
|
|||
|
|
@ -32,3 +32,14 @@ class HardwareInterface(ABC):
|
|||
True if hardware is initialized and ready.
|
||||
"""
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def set_digital_out(self, gpio: int, state: bool) -> None:
|
||||
"""
|
||||
Set a GPIO pin to HIGH or LOW.
|
||||
|
||||
Args:
|
||||
gpio: GPIO pin number.
|
||||
state: True for HIGH, False for LOW.
|
||||
"""
|
||||
...
|
||||
|
|
|
|||
|
|
@ -29,3 +29,7 @@ class RealHardware(HardwareInterface):
|
|||
def is_ready(self) -> bool:
|
||||
# TODO: check if Pi hardware nodes are reachable
|
||||
return True
|
||||
|
||||
def set_digital_out(self, gpio: int, state: bool) -> None:
|
||||
# TODO: publish to Pi hardware node
|
||||
self._logger.info(f"RealHardware.set_digital_out(gpio={gpio}, state={state}) — stub")
|
||||
|
|
|
|||
|
|
@ -3,17 +3,75 @@
|
|||
"languageVersion": 0,
|
||||
"blocks": [
|
||||
{
|
||||
"type": "controls_if",
|
||||
"id": "WLmpkq!^,rcoKGH+bQgN",
|
||||
"x": 210,
|
||||
"y": 70,
|
||||
"type": "controls_repeat_ext",
|
||||
"id": "j+usYB.X4%o``Le;Q,LA",
|
||||
"x": 190,
|
||||
"y": 150,
|
||||
"inputs": {
|
||||
"DO0": {
|
||||
"block": {
|
||||
"type": "led_on",
|
||||
"id": "._%j-2DZ*BZJlyW:1#`Q",
|
||||
"TIMES": {
|
||||
"shadow": {
|
||||
"type": "math_number",
|
||||
"id": "cI`]|Us0+)Ol~XY0L`wE",
|
||||
"fields": {
|
||||
"PIN": 1
|
||||
"NUM": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
"DO": {
|
||||
"block": {
|
||||
"type": "digitalOut",
|
||||
"id": "3}G7M%~([nNy9YHlug!|",
|
||||
"fields": {
|
||||
"GPIO": 17
|
||||
},
|
||||
"inputs": {
|
||||
"digitalOut": {
|
||||
"block": {
|
||||
"type": "logic_boolean",
|
||||
"id": "Sw__`~LvxpKyo}./q]1/",
|
||||
"fields": {
|
||||
"BOOL": "TRUE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"next": {
|
||||
"block": {
|
||||
"type": "delay",
|
||||
"id": "?o-l1IBd(^YR,u[;k$-|",
|
||||
"fields": {
|
||||
"DURATION_MS": 500
|
||||
},
|
||||
"next": {
|
||||
"block": {
|
||||
"type": "digitalOut",
|
||||
"id": "t}@.X|Ac7F?J;C4v`5ic",
|
||||
"fields": {
|
||||
"GPIO": 17
|
||||
},
|
||||
"inputs": {
|
||||
"digitalOut": {
|
||||
"block": {
|
||||
"type": "logic_boolean",
|
||||
"id": "]I]_@v6=ErAYdiolo|+n",
|
||||
"fields": {
|
||||
"BOOL": "FALSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"next": {
|
||||
"block": {
|
||||
"type": "delay",
|
||||
"id": "45BA([9g7/_tItSnUwB-",
|
||||
"fields": {
|
||||
"DURATION_MS": 500
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue