Skip to content

Commit 534445d

Browse files
author
Charles-Ellison
committed
add ServoGroup class
1 parent 73cf3ec commit 534445d

File tree

2 files changed

+282
-0
lines changed

2 files changed

+282
-0
lines changed

Adafruit_PWMServoDriverGroup.cpp

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#include "Adafruit_PWMServoDriverGroup.h"
2+
3+
/*!
4+
* @brief Instantiates new PCA9685 PWM driver chips with user defined
5+
* I2C addresses on a TwoWire interface
6+
* @param nDrivers Number of PWM driver chips to instantiate
7+
* @param nServosEach Number of servos to allocate on each driver
8+
* @param addr Array of 7-bit I2C addresses to locate the chips, default is 0x40 through 0x44
9+
*/
10+
Adafruit_PWMServoDriverGroup::Adafruit_PWMServoDriverGroup(const uint8_t nDrivers, const uint8_t nServosEach, const uint8_t *addr) {
11+
_nDrivers = nDrivers;
12+
_nServosEach = nServosEach;
13+
14+
_drivers = (Adafruit_PWMServoDriver **) malloc(nDrivers * sizeof(Adafruit_PWMServoDriver *));
15+
16+
for(uint8_t i=0; i < _nDrivers; i++) {
17+
_drivers[i] = new Adafruit_PWMServoDriver(addr[i], Wire);
18+
}
19+
}
20+
21+
/*!
22+
* @brief Instantiates new PCA9685 PWM driver chips with I2C addresses on a
23+
* TwoWire interface
24+
* @param nDrivers Number of PWM driver chips to instantiate
25+
* @param nServosEach Number of servos to allocate on each driver
26+
* @param addr Array of 7-bit I2C addresses to locate the chips, default is 0x40 thorugh 0x44
27+
* @param i2c A reference to a 'TwoWire' object that we'll use to communicate with
28+
*/
29+
Adafruit_PWMServoDriverGroup::Adafruit_PWMServoDriverGroup(const uint8_t nDrivers, const uint8_t nServosEach, const uint8_t *addr, TwoWire &i2c)
30+
{
31+
_nDrivers = nDrivers;
32+
_nServosEach = nServosEach;
33+
34+
_drivers = (Adafruit_PWMServoDriver **) malloc(nDrivers * sizeof(Adafruit_PWMServoDriver *));
35+
36+
for(uint8_t i=0; i < _nDrivers; i++) {
37+
_drivers[i] = new Adafruit_PWMServoDriver(addr[i], i2c);
38+
}
39+
}
40+
41+
/* @brief Gets the number of PCA9685 PWM driver chips connected to this class
42+
*/
43+
uint8_t Adafruit_PWMServoDriverGroup::getNumDrivers() {
44+
return _nDrivers;
45+
}
46+
47+
/* @brief Gets the number of servos associated with each PCA9685 PWM chip
48+
*/
49+
uint8_t Adafruit_PWMServoDriverGroup::getNumServosEach() {
50+
return _nServosEach;
51+
}
52+
53+
/* @brief Gets the total number of servos associated with this class
54+
*/
55+
uint8_t Adafruit_PWMServoDriverGroup::getNumServos() {
56+
return _nDrivers * _nServosEach;
57+
}
58+
59+
/*!
60+
* @brief Gets the Adafruit_PWMServoDriver associated with a given servo and
61+
* the local servo number on that device
62+
* @param num Number of servo in master list
63+
* @param localId returns the number of the servo as known to the PCA9685 chip
64+
* @return The Adafruit_PWMServoDriver associated with the requested servo
65+
*/
66+
Adafruit_PWMServoDriver* Adafruit_PWMServoDriverGroup::getDriver(uint8_t num, uint8_t& localId){
67+
uint8_t driverId = 0;
68+
if(num > _nServosEach - 1) driverId = num/_nServosEach;
69+
localId = num - (driverId * _nServosEach);
70+
71+
return _drivers[driverId];
72+
}
73+
74+
/*!
75+
* @brief Setups the I2C interface and hardware
76+
* @param prescale
77+
* Sets External Clock (Optional)
78+
* @return true if successful, otherwise false
79+
*/
80+
bool Adafruit_PWMServoDriverGroup::begin(uint8_t prescale) {
81+
bool status = true;
82+
for(int i = 0; i < _nDrivers; i++) status &= _drivers[i]->begin(prescale);
83+
84+
return status;
85+
}
86+
87+
/*!
88+
* @brief Sends a reset command to the PCA9685 chips over I2C
89+
*/
90+
void Adafruit_PWMServoDriverGroup::reset() {
91+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->reset();
92+
}
93+
94+
/*!
95+
* @brief Puts boards into sleep mode
96+
*/
97+
void Adafruit_PWMServoDriverGroup::sleep(){
98+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->sleep();
99+
}
100+
101+
/*!
102+
* @brief Wakes boards from sleep
103+
*/
104+
void Adafruit_PWMServoDriverGroup::wakeup(){
105+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->wakeup();
106+
}
107+
108+
/*!
109+
* @brief Sets EXTCLK pin to use the external clock
110+
* @param prescale
111+
* Configures the prescale value to be used by the external clock
112+
*/
113+
void Adafruit_PWMServoDriverGroup::setExtClk(uint8_t prescale){
114+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setExtClk(prescale);
115+
}
116+
117+
/*!
118+
* @brief Sets the PWM frequency for all chips, up to ~1.6 KHz
119+
* @param freq Floating point frequency that we will attempt to match
120+
*/
121+
void Adafruit_PWMServoDriverGroup::setPWMFreq(float freq){
122+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setPWMFreq(freq);
123+
}
124+
125+
/*!
126+
* @brief Sets the output mode of the PCA9685s to either
127+
* open drain or push pull / totempole.
128+
* Warning: LEDs with integrated zener diodes should
129+
* only be driven in open drain mode.
130+
* @param totempole Totempole if true, open drain if false.
131+
*/
132+
void Adafruit_PWMServoDriverGroup::setOutputMode(bool totempole){
133+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setOutputMode(totempole);
134+
}
135+
136+
/*!
137+
* @brief Gets the PWM output of one of the PCA9685 pins
138+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
139+
* @param off If true, returns PWM OFF value, otherwise PWM ON
140+
* @return requested PWM output value
141+
*/
142+
uint16_t Adafruit_PWMServoDriverGroup::getPWM(uint8_t num, bool off){
143+
uint8_t localId = 0;
144+
auto driver = getDriver(num, localId);
145+
return driver->getPWM(localId, off);
146+
}
147+
148+
/*!
149+
* @brief Sets the PWM output of one of the PCA9685 pins
150+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
151+
* @param on At what point in the 4096-part cycle to turn the PWM output ON
152+
* @param off At what point in the 4096-part cycle to turn the PWM output OFF
153+
* @return 0 if successful, otherwise 1
154+
*/
155+
uint8_t Adafruit_PWMServoDriverGroup::setPWM(uint8_t num, uint16_t on, uint16_t off){
156+
uint8_t localId = 0;
157+
auto driver = getDriver(num, localId);
158+
return driver->setPWM(localId, on, off);
159+
}
160+
161+
/*!
162+
* @brief Helper to set pin PWM output. Sets pin without having to deal with
163+
* on/off tick placement and properly handles a zero value as completely off and
164+
* 4095 as completely on. Optional invert parameter supports inverting the
165+
* pulse for sinking to ground.
166+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
167+
* @param val The number of ticks out of 4096 to be active, should be a value
168+
* from 0 to 4095 inclusive.
169+
* @param invert If true, inverts the output, defaults to 'false'
170+
*/
171+
void Adafruit_PWMServoDriverGroup::setPin(uint8_t num, uint16_t val, bool invert){
172+
uint8_t localId = 0;
173+
auto driver = getDriver(num, localId);
174+
driver->setPin(localId, val, invert);
175+
}
176+
177+
/*!
178+
* @brief Reads set Prescale from PCA9685
179+
* @return prescale value
180+
*/
181+
uint8_t Adafruit_PWMServoDriverGroup::readPrescale(){
182+
return _drivers[0]->readPrescale();
183+
}
184+
185+
/*!
186+
* @brief Sets the PWM output of one of the PCA9685 pins based on the input
187+
* microseconds, output is not precise
188+
* @param num One of the PWM output pins, from 0 to (nDrivers * nServosEach - 1)
189+
* @param Microseconds The number of Microseconds to turn the PWM output ON
190+
*/
191+
void Adafruit_PWMServoDriverGroup::writeMicroseconds(uint8_t num, uint16_t microseconds){
192+
uint8_t localId = 0;
193+
auto driver = getDriver(num, localId);
194+
195+
driver->writeMicroseconds(localId, microseconds);
196+
}
197+
198+
/*!
199+
* @brief Getter for the internally tracked oscillator used for freq
200+
* calculations
201+
* @returns The frequency the PCA9685 thinks it is running at (it cannot
202+
* introspect)
203+
*/
204+
uint32_t Adafruit_PWMServoDriverGroup::getOscillatorFrequency(uint8_t id){
205+
return _drivers[id]->getOscillatorFrequency();
206+
}
207+
208+
/*!
209+
* @brief Setter for the internally tracked oscillator used for freq
210+
* calculations
211+
* @param freq The frequency the PCA9685 should use for frequency calculations
212+
*/
213+
void Adafruit_PWMServoDriverGroup::setOscillatorFrequency(uint32_t freq){
214+
for(int i = 0; i < _nDrivers; i++) _drivers[i]->setOscillatorFrequency(freq);
215+
}
216+
217+
void Adafruit_PWMServoDriverGroup::setOscillatorFrequency(uint8_t id, uint32_t freq){
218+
_drivers[id]->setOscillatorFrequency(freq);
219+
}
220+
221+

Adafruit_PWMServoDriverGroup.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*!
2+
* @file Adafruit_PWMServoDriverGroup.h
3+
*
4+
* This Library sets up a group of Adafruit_PWMServoDrivers
5+
* to act like a single Adafruit_PWMServoDrivers object
6+
*
7+
*
8+
* Designed specifically to work with the Adafruit 16-channel PWM & Servo
9+
* driver.
10+
*
11+
* BSD license, all text above must be included in any redistribution
12+
*/
13+
#ifndef _ADAFRUIT_PWMServoDriverGroup_H
14+
#define _ADAFRUIT_PWMServoDriverGroup_H
15+
16+
#include "Adafruit_PWMServoDriver.h"
17+
18+
#define PCA9685_I2C_ADDRESS_1 0x40
19+
#define PCA9685_I2C_ADDRESS_2 0x41
20+
#define PCA9685_I2C_ADDRESS_3 0x42
21+
#define PCA9685_I2C_ADDRESS_4 0x43
22+
#define PCA9685_I2C_ADDRESS_5 0x44
23+
24+
/*!
25+
* @brief Class that stores state and functions for interacting with multiple PCA9685
26+
* PWM chips as if they are a single instance
27+
*/
28+
class Adafruit_PWMServoDriverGroup {
29+
public:
30+
31+
Adafruit_PWMServoDriverGroup(const uint8_t ndrivers, const uint8_t nServosEach, const uint8_t *addr);
32+
Adafruit_PWMServoDriverGroup(const uint8_t ndrivers, const uint8_t nServosEach, const uint8_t *addr, TwoWire &i2c);
33+
34+
Adafruit_PWMServoDriver* getDriver(uint8_t num, uint8_t& localNum);
35+
bool begin(uint8_t prescale = 0);
36+
void reset();
37+
void sleep();
38+
void wakeup();
39+
void setExtClk(uint8_t prescale);
40+
void setPWMFreq(float freq);
41+
void setOutputMode(bool totempole);
42+
uint16_t getPWM(uint8_t num, bool off = false);
43+
uint8_t setPWM(uint8_t num, uint16_t on, uint16_t off);
44+
void setPin(uint8_t num, uint16_t val, bool invert = false);
45+
uint8_t readPrescale(void);
46+
void writeMicroseconds(uint8_t num, uint16_t microseconds);
47+
void setOscillatorFrequency(uint32_t freq);
48+
void setOscillatorFrequency(uint8_t id, uint32_t freq);
49+
uint32_t getOscillatorFrequency(uint8_t id);
50+
51+
uint8_t getNumDrivers();
52+
uint8_t getNumServos();
53+
uint8_t getNumServosEach();
54+
55+
private:
56+
uint8_t _nDrivers;
57+
uint8_t _nServosEach;
58+
Adafruit_PWMServoDriver** _drivers;
59+
};
60+
61+
#endif

0 commit comments

Comments
 (0)