Skip to content

Commit a335606

Browse files
authored
Robot Mechanism Components (#108)
* Initial mechanisms and components * Can now increase/decrease inputs on mechanisms and components * Generate Python for mechanisms and components * Fix errors * Fixed where holder had to be before init to generate correctly * Move to have components and mechanisms like statements * remove unneeded files * Fixes typos * add more sample components to hardware category * Changes to add ports, get things more like we want * added update method * change orders and names of samples * change defaults for mechanism_start (for screenshot) * Have ports being passed in * add list of ports needed for mechanism * Clear the list of ports in finish * Remove the temporary init fields * No longer allow multiple components or mechanisms named the same Fixes #115 * Change leftover cut/paste error * Add details to OpMode Fixes #90 Fixe #91 * Fixed output for non-opmodes * Fix passing the correct thing to superclass init * Removed some unnecessary code
1 parent 0e19d63 commit a335606

20 files changed

+1158
-113
lines changed

src/blocks/mrc_class_method_def.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ export const pythonFromBlock = function (
458458
xfix2 = xfix1;
459459
}
460460
if(block.mrcPythonMethodName == '__init__'){
461-
branch = generator.INDENT + 'super().__init__(robot)\n' +
461+
let class_specific = generator.getClassSpecificForInit();
462+
branch = generator.INDENT + 'super().__init__(' + class_specific + ')\n' +
462463
generator.defineClassVariables() + branch;
463464
}
464465
if (returnValue) {
@@ -469,6 +470,10 @@ export const pythonFromBlock = function (
469470

470471
let params = block.mrcParameters;
471472
let paramString = "self";
473+
if (block.mrcPythonMethodName == '__init__') {
474+
paramString += generator.getListOfPorts(false);
475+
}
476+
472477
if (params.length != 0) {
473478
block.mrcParameters.forEach((param) => {
474479
paramString += ', ' + param.name;

src/blocks/mrc_component.ts

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Porpoiseful LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* @fileoverview Create a component with a name of a certain type
20+
* @author [email protected] (Alan Smith)
21+
*/
22+
import * as Blockly from 'blockly';
23+
import { Order } from 'blockly/python';
24+
25+
import { MRC_STYLE_COMPONENTS } from '../themes/styles'
26+
import { createFieldNonEditableText } from '../fields/FieldNonEditableText';
27+
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
28+
import { getAllowedTypesForSetCheck } from './utils/python';
29+
30+
export const BLOCK_NAME = 'mrc_component';
31+
export const OUTPUT_NAME = 'mrc_component';
32+
33+
export type ConstructorArg = {
34+
name: string,
35+
type: string,
36+
};
37+
38+
type ComponentExtraState = {
39+
importModule?: string,
40+
hideParams?: boolean,
41+
params?: ConstructorArg[],
42+
}
43+
44+
type ComponentBlock = Blockly.Block & ComponentMixin;
45+
interface ComponentMixin extends ComponentMixinType {
46+
mrcArgs: ConstructorArg[],
47+
hideParams: boolean,
48+
mrcImportModule: string,
49+
}
50+
type ComponentMixinType = typeof COMPONENT;
51+
52+
const COMPONENT = {
53+
/**
54+
* Block initialization.
55+
*/
56+
init: function (this: ComponentBlock): void {
57+
this.setStyle(MRC_STYLE_COMPONENTS);
58+
this.appendDummyInput()
59+
.appendField(new Blockly.FieldTextInput('my_mech'), 'NAME')
60+
.appendField('of type')
61+
.appendField(createFieldNonEditableText(''), 'TYPE');
62+
this.setPreviousStatement(true, OUTPUT_NAME);
63+
this.setNextStatement(true, OUTPUT_NAME);
64+
},
65+
66+
/**
67+
* Returns the state of this block as a JSON serializable object.
68+
*/
69+
saveExtraState: function (this: ComponentBlock): ComponentExtraState {
70+
const extraState: ComponentExtraState = {
71+
};
72+
extraState.params = [];
73+
this.mrcArgs.forEach((arg) => {
74+
extraState.params!.push({
75+
'name': arg.name,
76+
'type': arg.type,
77+
});
78+
});
79+
if (this.mrcImportModule) {
80+
extraState.importModule = this.mrcImportModule;
81+
}
82+
if (this.hideParams) {
83+
extraState.hideParams = this.hideParams;
84+
}
85+
return extraState;
86+
},
87+
/**
88+
* Applies the given state to this block.
89+
*/
90+
loadExtraState: function (this: ComponentBlock, extraState: ComponentExtraState): void {
91+
this.mrcImportModule = extraState.importModule ? extraState.importModule : '';
92+
this.hideParams = extraState.hideParams ? extraState.hideParams : false;
93+
this.mrcArgs = [];
94+
95+
if (extraState.params) {
96+
extraState.params.forEach((arg) => {
97+
this.mrcArgs.push({
98+
'name': arg.name,
99+
'type': arg.type,
100+
});
101+
});
102+
}
103+
this.mrcArgs = extraState.params ? extraState.params : [];
104+
this.updateBlock_();
105+
},
106+
/**
107+
* Update the block to reflect the newly loaded extra state.
108+
*/
109+
updateBlock_: function (this: ComponentBlock): void {
110+
if (this.hideParams == false) {
111+
// Add input sockets for the arguments.
112+
for (let i = 0; i < this.mrcArgs.length; i++) {
113+
const input = this.appendValueInput('ARG' + i)
114+
.setAlign(Blockly.inputs.Align.RIGHT)
115+
.appendField(this.mrcArgs[i].name);
116+
if (this.mrcArgs[i].type) {
117+
input.setCheck(getAllowedTypesForSetCheck(this.mrcArgs[i].type));
118+
}
119+
}
120+
}
121+
}
122+
}
123+
124+
export const setup = function () {
125+
Blockly.Blocks[BLOCK_NAME] = COMPONENT;
126+
}
127+
128+
export const pythonFromBlock = function (
129+
block: ComponentBlock,
130+
generator: ExtendedPythonGenerator,
131+
) {
132+
if (block.mrcImportModule) {
133+
generator.addImport(block.mrcImportModule);
134+
}
135+
let code = 'self.' + block.getFieldValue('NAME') + ' = ' + block.getFieldValue('TYPE') + '(';
136+
137+
for (let i = 0; i < block.mrcArgs.length; i++) {
138+
const fieldName = 'ARG' + i;
139+
if (i != 0) {
140+
code += ', '
141+
}
142+
if(block.hideParams){
143+
let extension = '';
144+
if(i != 0){
145+
extension = '_' + (i + 1).toString();
146+
}
147+
const newPort = block.getFieldValue('NAME') + extension + '_port';
148+
generator.addHardwarePort(newPort, block.mrcArgs[i].type);
149+
code += block.mrcArgs[i].name + " = " + newPort;
150+
}else{
151+
code += block.mrcArgs[i].name + ' = ' + generator.valueToCode(block, fieldName, Order.NONE);
152+
}
153+
}
154+
code += ')\n' + "self.hardware.append(self." + block.getFieldValue('NAME') + ")\n";
155+
return code;
156+
}

src/blocks/mrc_mechanism.ts

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import * as Blockly from 'blockly';
2323
import { Order } from 'blockly/python';
2424

25-
import { MRC_STYLE_FUNCTIONS } from '../themes/styles'
25+
import { MRC_STYLE_MECHANISMS } from '../themes/styles'
2626
import { createFieldNonEditableText } from '../fields/FieldNonEditableText';
2727
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
2828
import { getAllowedTypesForSetCheck } from './utils/python';
@@ -44,22 +44,22 @@ type MechanismBlock = Blockly.Block & MechanismMixin;
4444
interface MechanismMixin extends MechanismMixinType {
4545
mrcArgs: ConstructorArg[],
4646
mrcImportModule: string,
47-
4847
}
49-
type MechanismMixinType = typeof MECHANISM_FUNCTION;
48+
type MechanismMixinType = typeof MECHANISM;
5049

51-
const MECHANISM_FUNCTION = {
50+
const MECHANISM = {
5251
/**
5352
* Block initialization.
5453
*/
5554
init: function (this: MechanismBlock): void {
56-
this.setStyle(MRC_STYLE_FUNCTIONS);
55+
this.setStyle(MRC_STYLE_MECHANISMS);
5756
this.appendDummyInput()
5857
.appendField(new Blockly.FieldTextInput('my_mech'), 'NAME')
5958
.appendField('of type')
6059
.appendField(createFieldNonEditableText(''), 'TYPE');
61-
this.setPreviousStatement(true);
62-
this.setNextStatement(true);
60+
this.setPreviousStatement(true, OUTPUT_NAME);
61+
this.setNextStatement(true, OUTPUT_NAME);
62+
//this.setOutput(true, OUTPUT_NAME);
6363
},
6464

6565
/**
@@ -74,7 +74,7 @@ const MECHANISM_FUNCTION = {
7474
'name': arg.name,
7575
'type': arg.type,
7676
});
77-
});
77+
});
7878
if (this.mrcImportModule) {
7979
extraState.importModule = this.mrcImportModule;
8080
}
@@ -87,7 +87,7 @@ const MECHANISM_FUNCTION = {
8787
this.mrcImportModule = extraState.importModule ? extraState.importModule : '';
8888
this.mrcArgs = [];
8989

90-
if(extraState.params){
90+
if (extraState.params) {
9191
extraState.params.forEach((arg) => {
9292
this.mrcArgs.push({
9393
'name': arg.name,
@@ -101,42 +101,40 @@ const MECHANISM_FUNCTION = {
101101
/**
102102
* Update the block to reflect the newly loaded extra state.
103103
*/
104-
updateBlock_: function(this: MechanismBlock): void {
105-
// Add input sockets for the arguments.
106-
for (let i = 0; i < this.mrcArgs.length; i++) {
107-
const input = this.appendValueInput('ARG' + i)
108-
.setAlign(Blockly.inputs.Align.RIGHT)
109-
.appendField(this.mrcArgs[i].name);
110-
if (this.mrcArgs[i].type) {
111-
input.setCheck(getAllowedTypesForSetCheck(this.mrcArgs[i].type));
112-
}
104+
updateBlock_: function (this: MechanismBlock): void {
105+
// Add input sockets for the arguments.
106+
for (let i = 0; i < this.mrcArgs.length; i++) {
107+
const input = this.appendValueInput('ARG' + i)
108+
.setAlign(Blockly.inputs.Align.RIGHT)
109+
.appendField(this.mrcArgs[i].name);
110+
if (this.mrcArgs[i].type) {
111+
input.setCheck(getAllowedTypesForSetCheck(this.mrcArgs[i].type));
113112
}
114113
}
114+
}
115115
}
116116

117117
export const setup = function () {
118-
Blockly.Blocks[BLOCK_NAME] = MECHANISM_FUNCTION;
118+
Blockly.Blocks[BLOCK_NAME] = MECHANISM;
119119
}
120120

121121
export const pythonFromBlock = function (
122-
mechanismBlock: MechanismBlock,
122+
block: MechanismBlock,
123123
generator: ExtendedPythonGenerator,
124124
) {
125-
if (mechanismBlock.mrcImportModule) {
126-
generator.addImport(mechanismBlock.mrcImportModule);
125+
if (block.mrcImportModule) {
126+
generator.addImport(block.mrcImportModule);
127127
}
128-
generator.setHasMechanism();
129-
let code = 'self.mechanisms["' + mechanismBlock.getFieldValue('NAME') + '"] = '
130-
+ mechanismBlock.getFieldValue('TYPE') + '('
131-
for (let i = 0; i < mechanismBlock.mrcArgs.length; i++) {
132-
const fieldName = 'ARG' + i;
133-
if(i != 0){
134-
code += ', '
135-
}
136-
code += mechanismBlock.mrcArgs[i].name + ' = ' + generator.valueToCode(mechanismBlock, fieldName, Order.NONE);
128+
let code = 'self.' + block.getFieldValue('NAME') + ' = ' + block.getFieldValue('TYPE') + '(';
129+
130+
for (let i = 0; i < block.mrcArgs.length; i++) {
131+
const fieldName = 'ARG' + i;
132+
if (i != 0) {
133+
code += ', '
137134
}
138-
139-
code += ')' + "\n";
135+
code += block.mrcArgs[i].name + ' = ' + generator.valueToCode(block, fieldName, Order.NONE);
136+
}
137+
code += ')\n' + "self.hardware.append(self." + block.getFieldValue('NAME') + ")\n";
140138

141-
return code
139+
return code;
142140
}

0 commit comments

Comments
 (0)