My 10-year-old son went to a "Robotics Camp" and came home with a non-functional Arduino robot. I figured it shouldn't be too much trouble to get it working. He swears he had it operating at the camp, but our best efforts notwithstanding, we were unable to reproduce his successes at home to any degree at all. Currently we seem to have an ungainly, $400 paperweight.
I'm a .Net web-developer by day, but I'm completely uninitiated when it comes to Arduino. I did enough research to learn how to upload a basic sketch- the "Blink" sketch- to our board an verify that the board is functional. Upon uploading the Blink sketch we got a flashing red LED. I was able to go into the sketch and modify the the variable values and see the results in the duration of the LED flash after uploading the sketch again. So I'm confident that we have a good connection to the PC and a functioning Arduino board.
But beyond that I'm stumped. When I attempt to upload the program that my son brought home, the robot does nothing. I can see a red LED blink a few times on the Arduino, but other that that, nothing happens.
Here's some photos of our setup:
Here's the sketch that my son brought home:
/***************************************************
This is an example for our Adafruit 16-channel PWM & Servo driver
Servo test - this will drive 16 servos, one after the other
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/products/815
These displays use I2C to communicate, 2 pins are required to
interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, all text above must be included in any redistribution
****************************************************/
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
#include <QueueList.h>
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
// Depending on your servo make, the pulse width min and max may vary, you
// want these to be as small/large as possible without hitting the hard stop
// for max range. You'll have to tweak them as necessary to match the servos you
// have!
#define SERVOMIN 300//150 // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX 400//600 // this is the 'maximum' pulse length count (out of 4096)
uint16_t servoMins[] = {160, 200, 500, 150, 150, 150, 0};
uint16_t servoMaxs[] = {600, 600, 700, 600, 600, 600, 0};
uint16_t servoHomes[] = {380, 400, 300, 340, 375, 375, 0};
enum GroupType {WithPrevious, NewGroup};
#define PAUSE_COMMAND 6
#define NUM_TRANSITIONS (PAUSE_COMMAND+1)
unsigned long currentTime;
class transition
{
private:
unsigned long startTime;
unsigned long totalTime;
uint16_t pulseLenStart;
uint16_t pulseLenEnd;
uint16_t currentPulseLen;
int id;
bool transitioning;
public:
void init(int id, uint16_t current)
{
this->id = id;
currentPulseLen = current;
totalTime = 0;
startTime = 0;
pulseLenStart = current;
pulseLenEnd = current;
transitioning = false;
}
uint16_t calculate(unsigned long currentTime)
{
float t = 1.0f;
if (totalTime > 1e-3f)
t = (currentTime - startTime) / (float)totalTime;
t = (t > 1.0f) ? 1.0f : t;
currentPulseLen = (uint16_t)(((float)pulseLenEnd - (float)pulseLenStart) * t + pulseLenStart);
/* if (transitioning)
{
Serial.println("transitioning");
Serial.println(id);
Serial.println(t);
Serial.println(currentTime);
Serial.println(startTime);
Serial.println(totalTime);
Serial.println(pulseLenStart);
Serial.println(pulseLenEnd);
Serial.println(currentPulseLen);
}
*/
if (t >= 1.0f)
transitioning = false;
return currentPulseLen;
}
void createTransition (uint16_t pulseLen, unsigned long time)
{
/* Serial.println("create Transition:");
Serial.println(id);
Serial.println(pulseLen);
Serial.println(time);
*/
pulseLenStart = currentPulseLen;
pulseLenEnd = pulseLen;
totalTime = time;
startTime = currentTime;
transitioning = true;
}
bool isTransitioning()
{
return transitioning;
}
};
transition transitions[NUM_TRANSITIONS];
struct Command
{
uint16_t pulseLen;
unsigned long totalTime;
int commandType;
GroupType groupType;
void execute()
{
transitions[commandType].createTransition(pulseLen, totalTime);
}
};
QueueList<Command> commandQueue;
void program ();
void restoreHomePositions (double seconds);
void setup()
{
pwm.begin();
Serial.begin(9600);
Serial.println("Hello world");
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
for (int servoNum =0; servoNum < NUM_TRANSITIONS; servoNum++)
{
//pwm.setPWM(servoNum, 0, servoHomes[servoNum]);
transitions[servoNum].init(servoNum, servoHomes[servoNum]);
}
restoreHomePositions (0);
program();
restoreHomePositions (.75);
yield();
}
void processCommandQueue();
void loop()
{
currentTime = millis();
processCommandQueue();
for (int servoNum = 0; servoNum < NUM_TRANSITIONS; servoNum++)
{
if (transitions[servoNum].isTransitioning())
{
uint16_t pulselen = transitions[servoNum].calculate(currentTime);
if (servoNum != PAUSE_COMMAND)
{
pwm.setPWM(servoNum, 0, pulselen);
Serial.println("setPWM");
Serial.println(servoNum);
Serial.println(pulselen);
}
}
}
}
bool isTransitioning()
{
for (int servoNum = 0; servoNum < NUM_TRANSITIONS; servoNum++)
{
if (transitions[servoNum].isTransitioning())
return true;
}
return false;
}
int frame = 0;
void processCommandQueue()
{
if (!commandQueue.isEmpty())
{
Serial.println("Frame");
Serial.println(frame);
frame++;
}
if (!commandQueue.isEmpty() && !isTransitioning())
{
do
{
Command top = commandQueue.pop();
top.execute();
}
while (!commandQueue.isEmpty() && commandQueue.peek().groupType == WithPrevious);
}
}
void move (int commandType, uint16_t pulseLen, double seconds, GroupType groupType = NewGroup)
{
Command command;
command.groupType = groupType;
command.commandType = commandType;
command.pulseLen = pulseLen;
command.totalTime = (unsigned long)(seconds * 1000);
Serial.println("Command:");
Serial.println(groupType == NewGroup ? "NewGroup" : "WithPrevious");
Serial.println(commandType);
Serial.println(pulseLen);
Serial.println(command.totalTime);
commandQueue.push (command);
}
void rotateWrist (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[5], servoMaxs[5]);
move (5, pulseLen, seconds, groupType);
}
void bendWrist (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[4], servoMaxs[4]);
move (4, pulseLen, seconds, groupType);
}
void rotateForeArm (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[3], servoMaxs[3]);
move (3, pulseLen, seconds, groupType);
}
void bendForeArm (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[2], servoMaxs[2]);
move (2, pulseLen, seconds, groupType);
}
void bendUpperArm (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[1], servoMaxs[1]);
move (1, pulseLen, seconds, groupType);
}
void rotateRobot (int percent, double seconds, GroupType groupType = NewGroup)
{
percent = percent < -100 ? -100 : percent;
percent = percent > 100 ? 100 : percent;
uint16_t pulseLen = map (percent, -100, 100, servoMins[0], servoMaxs[0]);
move (0, pulseLen, seconds, groupType);
}
void pause (double seconds)
{
move (PAUSE_COMMAND, 0, seconds, NewGroup);
}
void restoreHomePositions (double seconds)
{
rotateRobot (0, seconds, NewGroup);
bendUpperArm (0, seconds, WithPrevious);
bendForeArm (0, seconds, WithPrevious);
rotateForeArm (0, seconds, WithPrevious);
bendWrist (0, seconds, WithPrevious);
rotateWrist (0, seconds, WithPrevious);
}
//This is where the program goes!
void program ()
{
//Available commands
/*rotateWrist (where, seconds, groupType)
bendWrist (where, seconds, groupType)
rotateForeArm (where, seconds, groupType)
bendForeArm (where, seconds, groupType)
bendUpperArm (where, seconds, groupType)
rotateRobot (where, seconds, groupType)
pause (seconds)*/
//example 1 -- rotates the wrist servo 100% over 2 seconds,
//starting a new transition group.
rotateWrist (100, 2);
//example 2 -- bends the upper arm and the forearm at the same time
//moving both 45% over 1.5 seconds.
bendUpperArm (45, 1.5);
bendForeArm (45, 1.5, WithPrevious);
bendForeArm(45, 1.7, WithPrevious);
}
//To start a new group, the groupType should be either NewGroup or left blank
//Any call after that set to WithPrevious will start the transition at the
//same time as the first transition in the group.
//As soon as a new call is made with a NewGroup groupType, a new transition group is m
// End of your program