Skip to content

Commit 7f45a5a

Browse files
committed
arduino code for 'ControlBox' with document describing protocol.
1 parent f0ec96b commit 7f45a5a

File tree

6 files changed

+487
-0
lines changed

6 files changed

+487
-0
lines changed

arduino/README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# ZAF 2.0 ControlBox
2+
3+
This is the Arduino code for ZAF's 2.0 'ControlBox'
4+
The control box centralises control to the valves, pumps,
5+
and servo and more
6+
7+
## How to install/update on the arduino:
8+
9+
The main sketch (controlbox) must be uploaded to _both_ arduino megas.
10+
Nothing else needs to be done.
11+
12+
## Connections:
13+
14+
The ControlBox firmware supports a nearly unlimited of chained arduinos,
15+
making the design infinitely scalable. We use serial connections via USB
16+
and UART at a speed of at 500'000 bps.
17+
18+
The first arduino in the chain receives messages per USB, messages are forwarded
19+
on the Serial1 port. Corresponding (Serial1) TX and RX lines must be connected
20+
to the RX and TX lines of the next arduino's Serial2. For the next arduinos in
21+
the chain the pattren is repeated: Serial1 to send to the next arduino,
22+
Serial2 to receive from the previous arduino. USB is operational for all arduinos
23+
in the chain but it is recommended to only inject messages at the beginning of
24+
the chain...
25+
26+
Pins 38 to 53 are reserved for valves. Pins 2 to 12 are reserved for PWM,
27+
with pin 7 reserved for 1 servo per arduino.
28+
29+
NOTE: arduino pins are _not_ the same than the PWM and Valve indexes!
30+
31+
## Protocol:
32+
33+
The ControlBox protocol is very simple and human-writable.
34+
The commands are received by the first arduino in the chain
35+
and if needed are forwarded recursively to the next arduinos.
36+
37+
### valve and PWM channels:
38+
39+
Each Arduino has 15 relay/valve channels, the 16th channel is
40+
used for the buzzer, and 10 PWM channels, of which channel 5 is
41+
reserved for servos. Valve channel of index 15 is therefore the 1st
42+
(index=0) valve channel of the second arduino. Each Arduino added
43+
inceases the number of available valve and PWM channels. The
44+
indexing starts at the first arduino and is incremented to span
45+
across all Arduinos ths offering a unified indexing.
46+
47+
### Command structure:
48+
49+
Commands always start with the character: '#' and end with '\n'.
50+
A successfully parsed command causes a return message of 'done!\n'.
51+
Integer numbers must be surrounded by some whitespace for delimitation
52+
(quite flexible n the type and number of whitespaces).
53+
54+
### Command list:
55+
56+
'#?\n'
57+
Returns the current state of the ControlBox.
58+
For example,for two arduinos chained, the result is:
59+
60+
|c|o|c|c|c|c|c|c|c|c|c|c|c|c|c||0|0|0|0|255|0|0|0|0|0|done!
61+
|o|c|c|c|c|c|c|c|c|c|c|c|c|c|c||0|0|0|0|0|0|0|0|0|0|done!
62+
63+
Where we can see that (second) valve 1 of the first arduino (first line)
64+
is open, and the (first) valve 0 of the second arduino (second line) is
65+
open. Also, the 5th PWM channel (index=4) of the first arduino is set at
66+
the max value of 255.
67+
68+
'#!\n'
69+
Shutsdown all valves and all PWMs and brings back all servos to position
70+
(angle) 0. This is called recursively on all arduinos in the chain.
71+
72+
'#dX\n'
73+
Turns on or off debugging messages: 'd0' --> off, 'd1' --> on.
74+
75+
'#b P D \n'
76+
Makes noise using the unnused relay (index=15).
77+
P is the periode in milliseconds, D is the duration in number of periods.
78+
79+
'#tT R I \n'
80+
Runs a test. There is two kinds of tests: 'v'alve and 'p'wm.
81+
Therefore T is either 'v' or 'p'. R is an integer that indicates
82+
how many times to repreat the test sequence.
83+
I is optional and only needed for the 'p' test, it indicates which PWM channel
84+
to use for the PWM test sequence.
85+
86+
'#vS I \n'
87+
Opens (S='o') or closes (S='c') valve at index I.
88+
89+
'#p I S \n'
90+
Sets the PWM value (or servo angle) of PWM channel I to value S.
91+
92+
Unrecognised commands are ignored (in debug mode a notification is sent.).
93+
94+
95+
96+
97+
98+
99+
100+
101+

arduino/controlbox/controlbox.ino

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
#define SAFETY_OFF_TIMEOUT 1000L*60L*5L // 5 minutes
3+
4+
long last_command_timestamp = 0;
5+
bool debug_output=false;
6+
7+
void setup()
8+
{
9+
setupSerial();
10+
setupValves();
11+
setupPWM();
12+
}
13+
14+
void loop()
15+
{
16+
loopSerial();
17+
loopValves();
18+
loopPWM();
19+
20+
if( last_command_timestamp>0 && (millis()-last_command_timestamp) > SAFETY_OFF_TIMEOUT)
21+
last_command_timestamp=-1;
22+
23+
delay(1000); // Loop runs once per second
24+
}

arduino/controlbox/pwm.ino

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
#define min_speed 30
3+
#define max_speed 255
4+
5+
#include <Servo.h>
6+
Servo myservo;
7+
8+
inline void setupPWM()
9+
{
10+
//Setup Channel B
11+
for(int i=0; i<10; i++)
12+
{
13+
pinMode(pwm_pin(i), OUTPUT);
14+
set_pwm_state(i, 0);
15+
}
16+
myservo.attach(7);
17+
18+
}
19+
20+
inline void print_pwm_status(HardwareSerial &serial)
21+
{
22+
serial.print('|');
23+
for(int i=0; i<10; i++)
24+
{
25+
serial.print(digitalRead(pwm_pin(i)), DEC);
26+
serial.print('|');
27+
}
28+
}
29+
30+
inline void loopPWM()
31+
{
32+
if( last_command_timestamp>0 && (millis()-last_command_timestamp) > SAFETY_OFF_TIMEOUT)
33+
turn_off_all_pwm();
34+
}
35+
36+
inline void turn_off_all_pwm()
37+
{
38+
for(int i=0; i<10; i++)
39+
set_pwm_state(i, 0);
40+
myservo.write(0);
41+
}
42+
43+
inline void set_pwm_state(uint8_t pwm_index, uint8_t pwm_value)
44+
{
45+
if(pwm_index==5)
46+
{
47+
myservo.write(constrain(pwm_value,0,200));
48+
}
49+
else
50+
{
51+
analogWrite(pwm_pin(pwm_index), pwm_value);
52+
53+
if(debug_output)
54+
{
55+
Serial.print("set_pwm_state(");
56+
Serial.print(pwm_index, DEC);
57+
Serial.print(",");
58+
Serial.print(pwm_value, DEC);
59+
Serial.println(")");
60+
}
61+
}
62+
}
63+
64+
65+
inline uint8_t pwm_pin(uint8_t pwm_index)
66+
{
67+
return 2+pwm_index;
68+
}

0 commit comments

Comments
 (0)