Skip to content

Commit d71b7ee

Browse files
changed servo mapping to enable attaching a servo to any supported digital or analog pin
1 parent 5235d18 commit d71b7ee

File tree

3 files changed

+106
-36
lines changed

3 files changed

+106
-36
lines changed

examples/ServoFirmata/ServoFirmata.ino

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,42 +12,49 @@
1212
/* This firmware supports as many servos as possible using the Servo library
1313
* included in Arduino 0017
1414
*
15-
* TODO add message to configure minPulse/maxPulse/degrees
16-
*
1715
* This example code is in the public domain.
1816
*/
1917

2018
#include <Servo.h>
2119
#include <Firmata.h>
2220

2321
Servo servos[MAX_SERVOS];
22+
byte servoPinMap[TOTAL_PINS];
23+
byte servoCount = 0;
2424

2525
void analogWriteCallback(byte pin, int value)
2626
{
27-
if (IS_PIN_SERVO(pin)) {
28-
servos[PIN_TO_SERVO(pin)].write(value);
29-
}
27+
if (IS_PIN_DIGITAL(pin)) {
28+
servos[servoPinMap[pin]].write(value);
29+
}
3030
}
3131

3232
void setup()
3333
{
34-
byte pin;
35-
36-
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
37-
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
38-
39-
for (pin=0; pin < TOTAL_PINS; pin++) {
40-
if (IS_PIN_SERVO(pin)) {
41-
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
42-
}
34+
byte pin;
35+
36+
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
37+
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
38+
39+
// attach servos from fist digital pin up to max number of
40+
// servos supported for the board
41+
for (pin = 0; pin < TOTAL_PINS; pin++) {
42+
if (IS_PIN_DIGITAL(pin)) {
43+
if (servoCount < MAX_SERVOS) {
44+
servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
45+
servoPinMap[pin] = servoCount;
46+
servoCount++;
47+
} else {
48+
Firmata.sendString("Max servos attached");
49+
}
4350
}
44-
45-
Firmata.begin(57600);
51+
}
52+
53+
Firmata.begin(57600);
4654
}
4755

4856
void loop()
4957
{
50-
while(Firmata.available())
51-
Firmata.processInput();
58+
while(Firmata.available())
59+
Firmata.processInput();
5260
}
53-

examples/StandardFirmata/StandardFirmata.ino

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved.
1414
Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved.
1515
Copyright (C) 2009 Shigeru Kobayashi. All rights reserved.
16-
Copyright (C) 2009-2013 Jeff Hoefs. All rights reserved.
16+
Copyright (C) 2009-2014 Jeff Hoefs. All rights reserved.
1717
1818
This library is free software; you can redistribute it and/or
1919
modify it under the terms of the GNU Lesser General Public
@@ -83,10 +83,55 @@ signed char queryIndex = -1;
8383
unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom()
8484

8585
Servo servos[MAX_SERVOS];
86+
byte servoPinMap[TOTAL_PINS];
87+
byte detachedServos[MAX_SERVOS];
88+
byte detachedServoCount = 0;
89+
byte servoCount = 0;
90+
91+
8692
/*==============================================================================
8793
* FUNCTIONS
8894
*============================================================================*/
8995

96+
void attachServo(byte pin, int minPulse, int maxPulse)
97+
{
98+
if (servoCount < MAX_SERVOS) {
99+
// reuse indexes of detached servos until all have been reallocated
100+
if (detachedServoCount > 0) {
101+
servoPinMap[pin] = detachedServos[detachedServoCount - 1];
102+
if (detachedServoCount > 0) detachedServoCount--;
103+
} else {
104+
servoPinMap[pin] = servoCount;
105+
servoCount++;
106+
}
107+
if (minPulse > 0 && maxPulse > 0) {
108+
servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
109+
} else {
110+
servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
111+
}
112+
setPinModeCallback(pin, SERVO);
113+
} else {
114+
Firmata.sendString("Max servos attached");
115+
}
116+
}
117+
118+
void detachServo(byte pin)
119+
{
120+
servos[servoPinMap[pin]].detach();
121+
// if we're detaching the last servo, decrement the count
122+
// otherwise store the index of the detached servo
123+
if (servoPinMap[pin] == servoCount && servoCount > 0) {
124+
servoCount--;
125+
} else if (servoCount > 0) {
126+
// keep track of detached servos because we want to reuse their indexes
127+
// before incrementing the count of attached servos
128+
detachedServoCount++;
129+
detachedServos[detachedServoCount - 1] = servoPinMap[pin];
130+
}
131+
132+
servoPinMap[pin] = 255;
133+
}
134+
90135
void readAndReportData(byte address, int theRegister, byte numBytes) {
91136
// allow I2C requests that don't require a register read
92137
// for example, some devices using an interrupt pin to signify new data available
@@ -180,8 +225,10 @@ void setPinModeCallback(byte pin, int mode)
180225
// the following if statements should reconfigure the pins properly
181226
disableI2CPins();
182227
}
183-
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
184-
servos[PIN_TO_SERVO(pin)].detach();
228+
if (IS_PIN_DIGITAL(pin) && mode != SERVO) {
229+
if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
230+
detachServo(pin);
231+
}
185232
}
186233
if (IS_PIN_ANALOG(pin)) {
187234
reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
@@ -226,10 +273,13 @@ void setPinModeCallback(byte pin, int mode)
226273
}
227274
break;
228275
case SERVO:
229-
if (IS_PIN_SERVO(pin)) {
276+
if (IS_PIN_DIGITAL(pin)) {
230277
pinConfig[pin] = SERVO;
231-
if (!servos[PIN_TO_SERVO(pin)].attached()) {
232-
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
278+
if (!servos[servoPinMap[pin]].attached()) {
279+
// servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
280+
// pass -1 for min and max pulse values to use default values set
281+
// by Servo library
282+
attachServo(pin, -1, -1);
233283
}
234284
}
235285
break;
@@ -251,8 +301,8 @@ void analogWriteCallback(byte pin, int value)
251301
if (pin < TOTAL_PINS) {
252302
switch(pinConfig[pin]) {
253303
case SERVO:
254-
if (IS_PIN_SERVO(pin))
255-
servos[PIN_TO_SERVO(pin)].write(value);
304+
if (IS_PIN_DIGITAL(pin))
305+
servos[servoPinMap[pin]].write(value);
256306
pinState[pin] = value;
257307
break;
258308
case PWM:
@@ -430,11 +480,11 @@ void sysexCallback(byte command, byte argc, byte *argv)
430480
int minPulse = argv[1] + (argv[2] << 7);
431481
int maxPulse = argv[3] + (argv[4] << 7);
432482

433-
if (IS_PIN_SERVO(pin)) {
434-
if (servos[PIN_TO_SERVO(pin)].attached())
435-
servos[PIN_TO_SERVO(pin)].detach();
436-
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
437-
setPinModeCallback(pin, SERVO);
483+
if (IS_PIN_DIGITAL(pin)) {
484+
if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
485+
detachServo(pin);
486+
}
487+
attachServo(pin, minPulse, maxPulse);
438488
}
439489
}
440490
break;
@@ -474,7 +524,7 @@ void sysexCallback(byte command, byte argc, byte *argv)
474524
Firmata.write(PWM);
475525
Firmata.write(8);
476526
}
477-
if (IS_PIN_SERVO(pin)) {
527+
if (IS_PIN_DIGITAL(pin)) {
478528
Firmata.write(SERVO);
479529
Firmata.write(14);
480530
}
@@ -550,25 +600,38 @@ void systemResetCallback()
550600
if (isI2CEnabled) {
551601
disableI2CPins();
552602
}
603+
604+
for (byte i=0; i < MAX_SERVOS; i++) {
605+
if (servoPinMap[i] < MAX_SERVOS) {
606+
//servos[servoPinMap[i]].detach();
607+
}
608+
}
609+
553610
for (byte i=0; i < TOTAL_PORTS; i++) {
554611
reportPINs[i] = false; // by default, reporting off
555612
portConfigInputs[i] = 0; // until activated
556613
previousPINs[i] = 0;
557614
}
558-
// pins with analog capability default to analog input
559-
// otherwise, pins default to digital output
615+
560616
for (byte i=0; i < TOTAL_PINS; i++) {
617+
// pins with analog capability default to analog input
618+
// otherwise, pins default to digital output
561619
if (IS_PIN_ANALOG(i)) {
562620
// turns off pullup, configures everything
563621
setPinModeCallback(i, ANALOG);
564622
} else {
565623
// sets the output to 0, configures portConfigInputs
566624
setPinModeCallback(i, OUTPUT);
567625
}
626+
627+
servoPinMap[i] = 255;
568628
}
569629
// by default, do not report any analog inputs
570630
analogInputsToReport = 0;
571631

632+
detachedServoCount = 0;
633+
servoCount = 0;
634+
572635
/* send digital inputs to set the initial state on the host computer,
573636
* since once in the loop(), this firmware will only send on change */
574637
/*

release.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ cd temp
1717
find . -name "*.DS_Store" -type f -delete
1818
zip -r Firmata.zip ./Firmata/
1919
cd ..
20-
mv ./temp/Firmata.zip Firmata-2.4.0-beta1.zip
20+
mv ./temp/Firmata.zip Firmata-2.4.0-beta2.zip
2121
rm -r ./temp

0 commit comments

Comments
 (0)