Skip to content

Commit 01f6854

Browse files
Merge pull request firmata#147 from firmata/servo-fix
expand range of pins servos can be attached to
2 parents 5235d18 + de7f988 commit 01f6854

File tree

4 files changed

+105
-34
lines changed

4 files changed

+105
-34
lines changed

examples/ServoFirmata/ServoFirmata.ino

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,42 +12,54 @@
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+
}
30+
}
31+
32+
void systemResetCallback()
33+
{
34+
servoCount = 0;
3035
}
3136

3237
void setup()
3338
{
34-
byte pin;
39+
byte pin;
3540

36-
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
37-
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
41+
Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
42+
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
43+
Firmata.attach(SYSTEM_RESET, systemResetCallback);
44+
45+
Firmata.begin(57600);
46+
systemResetCallback();
3847

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-
}
48+
// attach servos from first digital pin up to max number of
49+
// servos supported for the board
50+
for (pin = 0; pin < TOTAL_PINS; pin++) {
51+
if (IS_PIN_DIGITAL(pin)) {
52+
if (servoCount < MAX_SERVOS) {
53+
servoPinMap[pin] = servoCount;
54+
servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
55+
servoCount++;
56+
}
4357
}
44-
45-
Firmata.begin(57600);
58+
}
4659
}
4760

4861
void loop()
4962
{
50-
while(Firmata.available())
51-
Firmata.processInput();
63+
while(Firmata.available())
64+
Firmata.processInput();
5265
}
53-

examples/StandardFirmata/StandardFirmata.ino

Lines changed: 71 additions & 15 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,54 @@ 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+
} else {
113+
Firmata.sendString("Max servos attached");
114+
}
115+
}
116+
117+
void detachServo(byte pin)
118+
{
119+
servos[servoPinMap[pin]].detach();
120+
// if we're detaching the last servo, decrement the count
121+
// otherwise store the index of the detached servo
122+
if (servoPinMap[pin] == servoCount && servoCount > 0) {
123+
servoCount--;
124+
} else if (servoCount > 0) {
125+
// keep track of detached servos because we want to reuse their indexes
126+
// before incrementing the count of attached servos
127+
detachedServoCount++;
128+
detachedServos[detachedServoCount - 1] = servoPinMap[pin];
129+
}
130+
131+
servoPinMap[pin] = 255;
132+
}
133+
90134
void readAndReportData(byte address, int theRegister, byte numBytes) {
91135
// allow I2C requests that don't require a register read
92136
// for example, some devices using an interrupt pin to signify new data available
@@ -180,8 +224,10 @@ void setPinModeCallback(byte pin, int mode)
180224
// the following if statements should reconfigure the pins properly
181225
disableI2CPins();
182226
}
183-
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
184-
servos[PIN_TO_SERVO(pin)].detach();
227+
if (IS_PIN_DIGITAL(pin) && mode != SERVO) {
228+
if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
229+
detachServo(pin);
230+
}
185231
}
186232
if (IS_PIN_ANALOG(pin)) {
187233
reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
@@ -226,10 +272,12 @@ void setPinModeCallback(byte pin, int mode)
226272
}
227273
break;
228274
case SERVO:
229-
if (IS_PIN_SERVO(pin)) {
275+
if (IS_PIN_DIGITAL(pin)) {
230276
pinConfig[pin] = SERVO;
231-
if (!servos[PIN_TO_SERVO(pin)].attached()) {
232-
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
277+
if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
278+
// pass -1 for min and max pulse values to use default values set
279+
// by Servo library
280+
attachServo(pin, -1, -1);
233281
}
234282
}
235283
break;
@@ -251,8 +299,8 @@ void analogWriteCallback(byte pin, int value)
251299
if (pin < TOTAL_PINS) {
252300
switch(pinConfig[pin]) {
253301
case SERVO:
254-
if (IS_PIN_SERVO(pin))
255-
servos[PIN_TO_SERVO(pin)].write(value);
302+
if (IS_PIN_DIGITAL(pin))
303+
servos[servoPinMap[pin]].write(value);
256304
pinState[pin] = value;
257305
break;
258306
case PWM:
@@ -430,10 +478,11 @@ void sysexCallback(byte command, byte argc, byte *argv)
430478
int minPulse = argv[1] + (argv[2] << 7);
431479
int maxPulse = argv[3] + (argv[4] << 7);
432480

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);
481+
if (IS_PIN_DIGITAL(pin)) {
482+
if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
483+
detachServo(pin);
484+
}
485+
attachServo(pin, minPulse, maxPulse);
437486
setPinModeCallback(pin, SERVO);
438487
}
439488
}
@@ -474,7 +523,7 @@ void sysexCallback(byte command, byte argc, byte *argv)
474523
Firmata.write(PWM);
475524
Firmata.write(8);
476525
}
477-
if (IS_PIN_SERVO(pin)) {
526+
if (IS_PIN_DIGITAL(pin)) {
478527
Firmata.write(SERVO);
479528
Firmata.write(14);
480529
}
@@ -550,25 +599,32 @@ void systemResetCallback()
550599
if (isI2CEnabled) {
551600
disableI2CPins();
552601
}
602+
553603
for (byte i=0; i < TOTAL_PORTS; i++) {
554604
reportPINs[i] = false; // by default, reporting off
555605
portConfigInputs[i] = 0; // until activated
556606
previousPINs[i] = 0;
557607
}
558-
// pins with analog capability default to analog input
559-
// otherwise, pins default to digital output
608+
560609
for (byte i=0; i < TOTAL_PINS; i++) {
610+
// pins with analog capability default to analog input
611+
// otherwise, pins default to digital output
561612
if (IS_PIN_ANALOG(i)) {
562613
// turns off pullup, configures everything
563614
setPinModeCallback(i, ANALOG);
564615
} else {
565616
// sets the output to 0, configures portConfigInputs
566617
setPinModeCallback(i, OUTPUT);
567618
}
619+
620+
servoPinMap[i] = 255;
568621
}
569622
// by default, do not report any analog inputs
570623
analogInputsToReport = 0;
571624

625+
detachedServoCount = 0;
626+
servoCount = 0;
627+
572628
/* send digital inputs to set the initial state on the host computer,
573629
* since once in the loop(), this firmware will only send on change */
574630
/*

extras/revisions.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
FIRMATA 2.4.0 BETA - not yet released
22

33
[core library]
4+
* Changed the way servo pins are mapped to enable use of servos on
5+
a wider range of pins, including analog pins.
6+
* Updated FirmataServo example to use new pin mapping technique
47
* Changed sendValueAsTwo7bitBytes, startSysex and endSysex from private to
5-
* public methods.
8+
public methods.
69
* Added Intel Galileo to Boards.h
710
* Renamed FirmataSerial to FirmataStream
811
* Updated to latest Arduino library format

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)