Commit 91d69dca by Hubert

fixed queue, fixed sequences, refactored

1 parent 0915f162
No preview for this file type
#ifndef __CONTROL_H_ #ifndef __CONTROL_H_
#define __CONTROL_H_ #define __CONTROL_H_
#include "pump.h" #include "device.h"
void loop_control( int counter ); void loop_control( int counter );
......
#include "control.h" /* #include "control.h" */
void loop_control( int counter ) { void loop_control( int counter ) {
// i'm alive / heartbeat // i'm alive / heartbeat
/* pcf8574.digitalWrite(led, counter % 2); */ /* pcf8574.digitalWrite(led, counter % 2); */
if (button1->pressed) { if (button1->pressed) {
pump_start(button1); rotate_start(button1);
} }
if (button1->released) { if (button1->released) {
pump_end(button1); device_end(button1);
} }
/* unsigned int buttonCondition = buttonHolding; */ /* unsigned int buttonCondition = buttonHolding; */
......
#ifndef __PUMP_H_ #ifndef __DEVICE_H_
#define __PUMP_H_ #define __DEVICE_H_
/* #include <stdio.h> */
/* #include <string.h> */
/* #include <stdlib.h> */
/* #include <time.h> */
/* #include <stddef.h> */
#include <string.h> #include <string.h>
#include "pcf.h" #include "pcf.h"
#include "mqtt.h" #include "mqtt.h"
// Number = pcfPIN - one action per pin / no diode crap anymore // Number = pcfPIN - one action per pin / no diode crap anymore
#define dive 1 #define dive 1
#define diaphragm 2 #define diaphragm 2
#define peristaltic 3 #define peristaltic 3
#define peristaltic_reverse 4 #define peristaltic_reverse 4
#define src_valve_pump 5 #define src_valve_pump 5
#define dst_valve_rotate 6 #define dst_valve_rotate 6
#define dst_valve_flower 7u #define dst_valve_watersource 7
#define off 0 #define off 0
struct sequence { struct sequence {
struct action *action; struct action *action;
int pump; int device;
int src_valve; int start_value;
int dst_valve; int end_value;
double start; double start;
double end; double end;
struct sequence *next; struct sequence *next;
...@@ -37,13 +43,16 @@ int waterlevel = 0; ...@@ -37,13 +43,16 @@ int waterlevel = 0;
unsigned int pumpstate = 0; unsigned int pumpstate = 0;
unsigned long timeStored = 0; unsigned long timeStored = 0;
void loop_device();
int pump_start(struct action *ptr); void insertSequence(int device, int start_value, int end_value, double duration, struct action *action);
int pump_start(struct button *ptr); void next_sequence_step();
void pump_running(int remaining); void monitor_sequence_duration();
void pump_end(struct action *ptr);
void pump_end(struct button *ptr);
void pump_end(int source);
void set_relay(struct sequence *step); void set_relay(struct sequence *step);
int fill_start(struct action *ptr);
int rotate_start(struct action *ptr);
int rotate_start(struct button *ptr);
int fertilize_start(struct action *ptr);
#endif #endif
#include "device.h"
void insertSequence(int device, int start_value, int end_value, double duration, struct action *action) {
struct sequence *ptr = (struct sequence*) malloc(sizeof(struct sequence));
ptr->device = device;
ptr->start_value = start_value;
ptr->end_value = end_value;
ptr->action = action;
ptr->next = NULL;
Serial.println("is0");
if ( sequence_tail == NULL ) {
Serial.println("is1");
sequence_head = ptr;
set_relay(device, start_value);
ptr->end = action->start + duration;
} else {
Serial.println("is2");
sequence_tail->next = ptr;
ptr->start = sequence_tail->end;
ptr->end = sequence_tail->end + duration;
}
Serial.println("is3");
sequence_tail=ptr;
}
void loop_device() {
if ( sequence_tail != NULL ) { // there's something to do
monitor_sequence_duration();
next_sequence_step();
}
}
void next_sequence_step() {
unsigned int ut = time(NULL);
if ( ut >= sequence_head->end ) {
// set relay to end values of current step and start values of next step. afterwards remove the completed step;
if ( sequence_head->start_value != sequence_head->end_value ) {
set_relay(sequence_head->device, sequence_head->end_value);
}
struct sequence *tmp = (struct sequence*) malloc(sizeof(struct sequence));
tmp = sequence_head;
sequence_head = tmp->next;
if ( sequence_head != NULL ) {
set_relay(sequence_head->device, sequence_head->start_value);
next_sequence_step(); // in case the sequence duration is 0
} else {
sequence_tail = NULL;
}
free(tmp);
}
}
void monitor_sequence_duration() {
String pre = "home/compost/device/";
int device = sequence_head->device;
String duration(pre + device + "/duration");
unsigned int ut = time(NULL);
double remaining = sequence_head->end - ut;
String remainingStr(remaining);
Serial.println("--------------- Duration");
Serial.println(duration);
Serial.println(remainingStr);
Serial.println("---------------");
mqttClient.publish(duration, remainingStr );
}
int fill_start(struct action *ptr) {
if ( sequence_head == NULL ) {
insertSequence( dst_valve_rotate, 0, 0, 0, ptr );
insertSequence( dst_valve_watersource, 1, 1, 0, ptr );
insertSequence( src_valve_pump, 0, 0, 0, ptr );
insertSequence( peristaltic_reverse, 1, 0, 5, ptr ); // fill hose for 5 seconds
insertSequence( src_valve_pump, 1, 0, ptr->data, ptr ); // let gravity do its work
insertSequence( peristaltic, 1, 0, 5, ptr ); // vent hose for 5 seconds
insertSequence( dst_valve_watersource, 0, 0, 0, ptr );
return 1;
} else {
return 0;
}
}
int rotate_start(struct action *ptr) {
if ( sequence_head == NULL ) {
insertSequence( dst_valve_watersource, 0, 0, 0, ptr );
insertSequence( dst_valve_rotate, 1, 1, 0, ptr );
insertSequence( src_valve_pump, 1, 1, 0, ptr );
insertSequence( dive, 1, 0, ptr->data, ptr );
insertSequence( src_valve_pump, 0, 0, 0, ptr );
insertSequence( dst_valve_rotate, 0, 0, 0, ptr );
return 1;
} else {
return 0;
}
}
int rotate_start(struct button *ptr){
return 1;
}
int fertilize_start(struct action *ptr) {
if ( sequence_head == NULL ) {
insertSequence( dst_valve_watersource, 1, 1, 0, ptr );
insertSequence( dst_valve_rotate, 0, 0, 0, ptr );
insertSequence( src_valve_pump, 1, 1, 0, ptr );
insertSequence( dive, 1, 0, ptr->data, ptr );
insertSequence( src_valve_pump, 0, 0, 0, ptr );
insertSequence( dst_valve_rotate, 0, 0, 0, ptr );
insertSequence( dst_valve_watersource, 0, 0, 0, ptr );
return 1;
} else {
return 0;
}
}
void set_relay(int device, int value) {
String pre = "home/compost/device/";
/* int device = sequence_head->device; */
String state(pre + device + "/state");
String valueStr( value );
mqttClient.publish(state, valueStr );
Serial.println("--------------- Relay");
Serial.println(state);
Serial.println(valueStr);
Serial.println("---------------");
int pin = 1;
while ( pin < 7 ) {
if ( device == pin
/* || step->src_valve == pin */
/* || step->dst_valve == pin */
) {
/* pcf8574.digitalWrite(pin,0); */
} else {
/* pcf8574.digitalWrite(pin,1); */
}
pin++;
}
}
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include "pcf.h" #include "pcf.h"
#include "mqtt.h" #include "mqtt.h"
#include "queue.h" #include "queue.h"
#include "pump.h" #include "device.h"
#include "control.h"
/* #include "control.h" */
/* #include "control.h" */
unsigned int counter = 0; unsigned int counter = 0;
...@@ -18,23 +20,26 @@ void setup(void) { ...@@ -18,23 +20,26 @@ void setup(void) {
Serial.begin(115200); Serial.begin(115200);
delay(100); delay(100);
setup_wifi(); setup_wifi();
pinMode(LED_BUILTIN, OUTPUT);
setup_sonar(); setup_sonar();
setup_pcf(); setup_pcf();
setup_mqtt(); setup_mqtt();
setup_queue(); /* setup_queue(); */
} }
void loop(void) { void loop(void) {
MDNS.update(); MDNS.update();
delay(500); delay(500);
counter++; counter++;
loop_sonar(counter); loop_sonar(counter);
String liquidLevelAvgStr(liquid_level_avg()); /* String liquidLevelAvgStr(liquid_level_avg()); */
mqttClient.publish(PREAMBLE T_SDIST, liquidLevelAvgStr ); /* mqttClient.publish(PREAMBLE T_SDIST, liquidLevelAvgStr ); */
loop_pcf(); loop_pcf();
loop_queue(); loop_queue();
loop_control(counter); loop_device();
next_sequence_step(); /* loop_control(counter); */
} }
...@@ -18,6 +18,17 @@ MQTT mqttClient(device_id, mqtt_server, 1883); ...@@ -18,6 +18,17 @@ MQTT mqttClient(device_id, mqtt_server, 1883);
#define T_PUMPDURATION "pumpduration" #define T_PUMPDURATION "pumpduration"
#define T_PUMPABORT "pumpabort" #define T_PUMPABORT "pumpabort"
#define T_FILL "fill/"
#define T_ROTATE "rotate/"
#define T_FERTILIZE "fertilize/"
#define TS_DURATION "duration"
#define TS_LEVEL "level"
#define C_FILL_DURATION 0
#define C_ROTATE_DURATION 1
#define C_FERTILIZE_DURATION 2
long stringToLong(String s); long stringToLong(String s);
void setup_mqtt(); void setup_mqtt();
void mqttSubscribe(); void mqttSubscribe();
......
...@@ -18,9 +18,10 @@ void setup_mqtt() { ...@@ -18,9 +18,10 @@ void setup_mqtt() {
void mqttSubscribe() { void mqttSubscribe() {
/* mqttClient.subscribe("home/compost/pump"); */ /* mqttClient.subscribe("home/compost/pump"); */
mqttClient.subscribe(PREAMBLE T_PUMPDURATION,1); Serial.println("mqttSubscribe");
mqttClient.subscribe(PREAMBLE T_PUMPLEVEL,1); mqttClient.subscribe(PREAMBLE T_FILL TS_DURATION,1);
mqttClient.subscribe(PREAMBLE T_PUMPABORT,1); mqttClient.subscribe(PREAMBLE T_ROTATE TS_DURATION ,1);
mqttClient.subscribe(PREAMBLE T_FERTILIZE TS_DURATION ,1);
/* Serial.println("subscribed to" PREAMBLE T_PUMPDURATION); */ /* Serial.println("subscribed to" PREAMBLE T_PUMPDURATION); */
} }
...@@ -40,15 +41,25 @@ void mqttDisconnected() { ...@@ -40,15 +41,25 @@ void mqttDisconnected() {
} }
void mqttData(String& topic, String& data) { void mqttData(String& topic, String& data) {
Serial.println("mqttData");
String dataStr(data); String dataStr(data);
/* mqttClient.publish(PREAMBLE T_PUMPSTATE, dataStr ); */ Serial.println(topic);
if (topic == PREAMBLE T_PUMPDURATION) { Serial.println(PREAMBLE T_FILL TS_DURATION);
insert("pumpduration", time(NULL), stringToLong(dataStr), 0); if (topic == PREAMBLE T_FILL TS_DURATION) {
Serial.println("rotate duration");
enqueue(C_FILL_DURATION, time(NULL), stringToLong(dataStr));
} }
if (topic == PREAMBLE T_PUMPLEVEL) { if (topic == PREAMBLE T_ROTATE TS_DURATION) {
insert("pumplevel", time(NULL), 1, stringToLong(dataStr)); enqueue(C_ROTATE_DURATION, time(NULL), stringToLong(dataStr));
} }
if (topic == PREAMBLE T_PUMPABORT) { if (topic == PREAMBLE T_FERTILIZE TS_DURATION) {
insert("pumpabort", 0, 0, 0); enqueue(C_FERTILIZE_DURATION, time(NULL), stringToLong(dataStr));
} }
/* if (topic == PREAMBLE T_PUMPLEVEL) { */
/* enqueue("pumplevel", time(NULL), stringToLong(dataStr)); */
/* } */
/* if (topic == PREAMBLE T_PUMPABORT) { */
/* enqueue("pumpabort", 0, 0); */
/* } */
} }
#include "pump.h"
void insertSequence(int pump, int src_valve, int dst_valve, double duration, struct action *action) {
unsigned int ut = time(NULL);
struct sequence *ptr = (struct sequence*) malloc(sizeof(struct sequence));
sequence_tail->next = ptr;
if ( sequence_head == NULL ) {
sequence_head = ptr;
ptr->end = ut + duration;
ptr->start = ut;
}
ptr->pump = pump;
ptr->src_valve = src_valve;
ptr->dst_valve = dst_valve;
ptr->start = sequence_tail->start;
ptr->end = sequence_tail->end + duration;
ptr->action = action;
ptr->next = NULL;
sequence_tail=ptr;
}
void next_sequence_step() {
if ( sequence_head != NULL ) { // there's something to do
unsigned int ut = time(NULL);
if ( ut >= sequence_head->end ) { // do next step
struct sequence *tmp = (struct sequence*) malloc(sizeof(struct sequence));
tmp = sequence_head;
sequence_head = tmp->next;
if ( sequence_head != NULL ) {
set_relay(sequence_head);
}
free(tmp);
}
}
}
int pump_start(struct action *ptr) {
if ( sequence_head == NULL ) {
String remainingStr(ptr->duration);
mqttClient.publish(PREAMBLE T_PUMPSTATE, remainingStr);
insertSequence( dive, src_valve_pump, dst_valve_rotate, ptr->duration, ptr );
insertSequence( off , off , off , 0 , ptr );
set_relay(sequence_head); // kickoff sequence
return 1;
} else {
return 0;
}
}
int pump_start(struct button *ptr){
return 1;
}
void pump_running(struct action *ptr) {
unsigned int ut = time(NULL);
String remainingStr(ptr->end - ut);
mqttClient.publish(PREAMBLE T_PUMPSTATE, remainingStr );
}
void pump_end(struct action *ptr) {
// abort
/* pcf8574.digitalWrite(leeren11, 1); */
/* pcf8574.digitalWrite(leeren1, 1); */
/* pcf8574.digitalWrite(leeren2, 1); */
/* pcf8574.digitalWrite(fuellen2, 1); */
String remainingStr(0);
mqttClient.publish(PREAMBLE T_PUMPSTATE, remainingStr );
}
void pump_end(struct button *ptr) {
}
void pump_end(int source) {
}
void set_relay(struct sequence *step) {
int pin = 1;
while ( pin < 7 ) {
if ( step->pump == pin
|| step->src_valve == pin
|| step->dst_valve == pin
) {
/* pcf8574.digitalWrite(pin,0); */
} else {
/* pcf8574.digitalWrite(pin,1); */
}
pin++;
}
}
...@@ -6,15 +6,14 @@ ...@@ -6,15 +6,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include <stddef.h> #include <stddef.h>
#include "pump.h" #include "device.h"
struct action { struct action {
char *command; int command;
int running; int running;
double start; double start;
double duration; double data;
double end; double end;
int level;
struct action *next; struct action *next;
}; };
...@@ -22,9 +21,15 @@ struct action *head = NULL; ...@@ -22,9 +21,15 @@ struct action *head = NULL;
struct action *tail = NULL; struct action *tail = NULL;
struct action *current = NULL; struct action *current = NULL;
void insert(char *command, double start, double duration, int level); void enqueue(int command, double start, double duration, int level);
/* void insert(char *command, unsigned int start, int duration, int level); */
void loop_queue(); void loop_queue();
void setup_queue(); void setup_queue();
void entry_running(struct action *ptr);
int entry_start(struct action *ptr);
void entry_end(struct action *ptr);
void entry_end(struct button *ptr);
void entry_end(int source);
#endif #endif
#include "queue.h" #include "queue.h"
void insert(char *command, double start, double duration, int level) { void enqueue(int command, double start, double data) {
struct action *ptr = head; Serial.println("enqueue");
// no dupes, only create new if it is scheduled /* // no dupes, only create new if it is scheduled */
while(ptr != NULL) { /* while(ptr != NULL) { */
if ( command == T_PUMPLEVEL /* if ( command == T_PUMPLEVEL */
|| command == T_PUMPDURATION /* || command == T_PUMPDURATION */
|| command == T_PUMPABORT /* || command == T_PUMPABORT */
&& /* && */
ptr->command == T_PUMPLEVEL /* ptr->command == T_PUMPLEVEL */
|| ptr->command == T_PUMPDURATION /* || ptr->command == T_PUMPDURATION */
) { /* ) { */
break; /* break; */
} /* } */
/* } */
struct action *ptr = (struct action*) malloc(sizeof(struct action));
ptr->command = command;
ptr->start = start;
ptr->data = data;
ptr->next = NULL;
ptr->running = 0;
if (head == NULL) {
head = ptr;
} }
if ( ptr == NULL ) { if (tail != NULL) {
ptr = (struct action*) malloc(sizeof(struct action)); tail->next = ptr;
ptr->next = NULL; }
ptr->command = command; tail = ptr;
ptr->running = 0;
/* struct action *ptr = head; */
/* if ( ptr == NULL ) { */
// in an empty list, this is head // in an empty list, this is head
if (head == NULL) {
head = ptr;
}
// previous tail is not last anymore // previous tail is not last anymore
if (tail != NULL) {
tail->next = ptr;
}
// this is now tail // this is now tail
tail = ptr; /*
/* } */
/* if ( command == T_PUMPABORT ) { */
/* ptr->end = 1; */
/* ptr->running = 1; */
/* } else { */
/* } */
}
int entry_start(struct action *ptr) {
switch( ptr->command ) {
case C_FILL_DURATION:
return fill_start(ptr);
case C_ROTATE_DURATION:
return rotate_start(ptr);
case C_FERTILIZE_DURATION:
return fertilize_start(ptr);
} }
if ( command == T_PUMPABORT ) { return 0;
ptr->end = 1; }
ptr->running = 1;
} else { void entry_running(struct action *ptr) {
ptr->start = start; unsigned int ut = time(NULL);
ptr->duration = duration; String remainingStr(ptr->end - ut);
ptr->level = level; delay(10); // Don't remove! mqttClient crashes otherwise
switch( ptr->command ) {
case C_FILL_DURATION:
mqttClient.publish("home/compost/action/3/duration", remainingStr );
break;
case C_ROTATE_DURATION:
mqttClient.publish("home/compost/action/1/duration", remainingStr );
break;
case C_FERTILIZE_DURATION:
mqttClient.publish("home/compost/action/2/duration", remainingStr );
break;
} }
} }
/* void device_running(struct action *ptr) { */
/* /\* int device = sequence_head->device; *\/ */
/* /\* String pre = "home/compost/device/"; *\/ */
/* /\* int device = 1; *\/ */
/* /\* String state(pre + device + "state"); *\/ */
/* /\* String duration(pre + device + "/duration"); *\/ */
/* } */
void entry_end(struct action *ptr) {
String remainingStr(0);
mqttClient.publish(PREAMBLE T_PUMPSTATE, remainingStr );
}
void entry_end(struct button *ptr) {
}
void entry_end(int source) {
}
void loop_queue() { void loop_queue() {
struct action *ptr = head; struct action *ptr = head;
struct action *next = NULL; struct action *next = NULL;
...@@ -51,38 +104,30 @@ void loop_queue() { ...@@ -51,38 +104,30 @@ void loop_queue() {
while(ptr != NULL) { while(ptr != NULL) {
next=ptr->next; next=ptr->next;
Serial.println("---------------");
Serial.println(ptr->command);
Serial.println(ptr->running);
Serial.println(ut);
Serial.println(ptr->start);
Serial.println(ptr->end);
Serial.println(ptr->duration);
Serial.println("---------------");
///////////////////////// start action
if ( ptr->running == 0 if ( ptr->running == 0
&& ut >= ptr->start && ut >= ptr->start
) { ) {
if ( pump_start(ptr) ) { // pump is blocked ? if ( entry_start(ptr) ) { // pump is blocked ?
ptr->end = ptr->duration + ut; ptr->end = ptr->data + ut;
ptr->running = 1; ptr->running = 1;
} else { } else {
ptr->start++; ptr->start++; // delay action;
} }
} }
///////////////////////// action ///////////////////////// action
if ( ptr->running == 1 ) { if ( ptr->running == 1 ) {
pump_running(ptr); entry_running(ptr);
} }
///////////////////////// end action ///////////////////////// end action
if ( ptr->running == 1 if ( ptr->running == 1
&& ut >= ptr->end && ut >= ptr->end
) { ) {
pump_end(ptr); Serial.println("end");
entry_end(ptr);
Serial.println("end1");
/* action is due to removal */ /* action is due to removal */
if (prev != NULL) { if (prev != NULL) {
...@@ -92,10 +137,10 @@ void loop_queue() { ...@@ -92,10 +137,10 @@ void loop_queue() {
if (ptr == head) { if (ptr == head) {
head = ptr->next; head = ptr->next;
} }
Serial.println("end5");
if (ptr == tail) { /* if (ptr == tail) { */
tail = prev; /* tail = prev; */
} /* } */
free(ptr); free(ptr);
} else { } else {
prev = ptr; prev = ptr;
......
include<vars.scad> include<vars.scad>
module cornerdrills() { module cornerdrills() {
translate([3.9,0.8,0]) { translate([2.4,0.8,0]) {
cylinder(d=1.2,h=4, $fn=10); cylinder(d=1.2,h=4, $fn=10);
} }
translate([2.4,0.8,0]) { translate([2.4,0.8,0]) {
...@@ -17,7 +17,7 @@ module cornerdrills() { ...@@ -17,7 +17,7 @@ module cornerdrills() {
translate([0,1.5,0]) cylinder(d=0.6,h=40, $fn=10); translate([0,1.5,0]) cylinder(d=0.6,h=40, $fn=10);
} }
} }
translate([0.8,3.9,10]) { translate([0.8,2.4,10]) {
cylinder(d=1.2,h=20, $fn=10); cylinder(d=1.2,h=20, $fn=10);
} }
} }
......
...@@ -122,7 +122,6 @@ module eurobox(x,y,z,handle,handlecaps,pipes,drilled,screws,locked,exploded) { ...@@ -122,7 +122,6 @@ module eurobox(x,y,z,handle,handlecaps,pipes,drilled,screws,locked,exploded) {
} }
if ( drilled ) drills(x,y,z); if ( drilled ) drills(x,y,z);
} }
} }
/* eurobox(30,40,22,true); */ /* eurobox(30,40,22,true); */
......
include<eurobox.scad> include<eurobox.scad>
include<lid.scad> include<lid.scad>
/* translate([0,0,2]) euroboxlid(30,40); */ /* #translate([0,0,4.56]) euroboxlid(30,40); */
/* translate([0,0,-7]) */
/* eurobox(30,40,7,handle=false); */
/* translate([0,0,6.3]) */ /* translate([7,3,0.9]) difference(){ */
/* eurobox(30,40,22, */ /* union() { */
/* handle=true, */ /* cube([ 15.2 */
/* handlecaps=true, */ /* , 23.2 */
/* pipes=true, */ /* , 3.6 */
/* drilled=true, */ /* ]); */
/* screws=true, */ /* translate([-0.57,-0.57,3]) cube([ 15 + 0.57*2 */
/* locked=true, */ /* , 23 + 0.57*2 */
/* exploded=false */ /* , 0.612 */
/* ); */ /* ]); */
/* } */
/* translate([0.1,0.1,0.1]) cube([ 15 */
/* , 23 */
/* , 3.6 */
/* ]); */
/* } */
/* translate([0,0,0]) euroboxlid(30,40); */
/* translate([0,0,-7]) */
/* eurobox(30,40,7,handle=false); */
translate([0,0,6.3+21.3/* +4 */]) translate([0,0,5.31])
eurobox(30,40,22, eurobox(30,40,22,
handle=true, handle=true,
handlecaps=true, handlecaps=true,
...@@ -26,6 +35,18 @@ eurobox(30,40,22, ...@@ -26,6 +35,18 @@ eurobox(30,40,22,
drilled=true, drilled=true,
screws=true, screws=true,
locked=true, locked=true,
exploded=true exploded=false
); );
/* translate([0,0,6.3+21.3/\* +4 *\/]) */
/* eurobox(30,40,22, */
/* handle=true, */
/* handlecaps=true, */
/* pipes=true, */
/* drilled=true, */
/* screws=true, */
/* locked=true, */
/* exploded=true */
/* ); */
...@@ -92,3 +92,4 @@ module screws(x,y,z, locked, exploded) { ...@@ -92,3 +92,4 @@ module screws(x,y,z, locked, exploded) {
mirror([1,0,0]) translate([-x,0,0]) cornerscrews(22, exploded, locked); mirror([1,0,0]) translate([-x,0,0]) cornerscrews(22, exploded, locked);
mirror([1,0,0]) translate([-x,y,0]) mirror([0,1,0]) cornerscrews(22, exploded, locked); mirror([1,0,0]) translate([-x,y,0]) mirror([0,1,0]) cornerscrews(22, exploded, locked);
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!