What causes DevOps Burnout? (San Francisco special)

In response to my last post, I was sent an Email asking what causes burnout and why people are still passionate about their jobs despite how stressful they are. The following was my Email response:

Every experience is individual and I can only expand on my own, but I will offer what perspective I can. In my environment and among my peers, I have noticed the following:

The Landscape: 

  • People experienced to work in a DevOps environment seem very difficult to find, but that perception is heavily concentrated here in San Francisco. There are people all over the country and world with the talents we compete over hiring in the Bay. 
  • Counterpoint: Given how much "more personal" DevOps organizations are when compared to traditional development workplaces, something might be lost if they are primarily off-site. The same bonds won't form and the very valuable "drop in and learn" time will be unavailable. 
  • New startups are popping up every week and all are trying to fish from the same talent pool. Companies are having difficulty attracting loyalty that goes beyond the biweekly check. 
  • Too many people - especially the younger crowd - want to work at a pre-IPO startup for three years, flip stock, and be rich. They don't mind packing five people into a two-bedroom apartment. They overwork themselves for the short-term success of their product, even recreational use of Ritalin so they can code for sixteen hours at a stretch.
  • One more salient, uniquely "San Francisco" problem is the housing crisis. I feel I am well paid and already moved out of mid-Market after only a single year, but I still think that I could be homeless far too quickly if something happened to my job. There are people around me who know their $6000 monthly take-hope is more than anyone else in their family, but housing still robs them of the ability to survive even two months without a job.

The Hard Job: 

  • From an Operations standpoint, the job is relatively thankless. A wonderful operations engineer is one whose work you never see. The flow from concept to architecture to infrastructure to platform is nearly invisible in a post-datacenter world. When everything is silent, your Operations staff is doing a great job.
  • The product (web app, something-as-a-service, or whatever) gets all the design awards, new features, and revenue streams, but the platform is ALWAYS a cost center. When a startup goes from "do everything we can to make a great product" to "do everything we can to boost the share price," the cost center jobs usually get put under greater scrutiny. 
  • Because innovation moves so fast, we are always expected to be on the cutting edge of automation, integration, continuous delivery, security, and more. It's hard to keep up and not all companies give their staff time to attend group events like DevOps Days.
  • It's actually pretty technically difficult - and continuous experimentation and work is required to keep up.

Why are we so passionate about this? Well I'm interested in your theories and I can tell you why I am so passionate about my role.

  • Because innovation moves so fast. While it is difficult, it is still very exciting to implement a new tool or workflow that shaves hours of work off every week.
  • It's actually pretty technically difficult. While this is also a challenge, it is a very satisfying one to overcome. 
  • This is probably not common, but I particularly enjoy being in the background. I love it when smarter-than-me developers need a specific kind of build and toolchain to be successful - even if my work is never seen by the customer. I have a fondness for a sort of "wind beneath the wings" role. 
  • Spreading the work and ideas around - especially in jobs that promote open-source contribution, is continually rewarding over time. Seeing a trick you hacked together show up months later in someone's presentation is very flattering - especially if credit is given.
  • What is true with code is also true with compassion and philosophy: Having a good idea, sharing it, and collecting good ideas from others makes everyone smarter, better, and nicer.

Burnout, fatigue, depression, and DevOps

This post, published 8/30/2015, is a first draft and is posted specifically to solicit feedback. I admit the limitations in my knowledge and encourage medical professionals, psychologists, HR managers, employment lawyers, and career counselors to submit additions and corrections.

While at DevOps Days Chicago 2015, I was privileged to take part in a conversation about burnout, depression, and how to approach it with a DevOps sympathetic problem-solving attitude. Over the course of my life, I have had to face anxiety issues, emotional issues, and job burnout. I have had some luck with psychiatry, employee resources, good managers, and studies on my own, so I will share what I have learned over my journey. Hopefully this will help a struggling worker or a sympathetic manager to find ways of preventing or coping with burnout.

I will preface this by saying I am not a doctor or trained psychologist nor has this blog post been reviewed by any medical professional. Please don’t take this as medical advice and if you feel you or anyone is in danger of self-harm or harming others, call your emergency services (911 in the US) right away and they can find help.


I like to tell people that there are only four things in the world that make anyone happy. Those are epinephrine, norepinephrine, serotonin, and dopamine. Everything else we do is a way of generating or balancing those four neurotransmitters. There are other things that exacerbate our reactions to things (for example: danger, physical pain, or high blood pressure can change emotional states) but the presence and balance of these four neurotransmitters are a good indication of  happiness.

This is important to know because all of the symptoms and states described below have some impact on brain chemistry. Neuropsychology is hard work and it is not my field of study so I'll leave the technical details. Just remember: If a person is exhibiting symptoms of stress, anxiety, depression or burnout, ask yourself, "Is this person unhappy because of a bad situation or is a bad situation arising from unhappiness?" 

It is possible for one to cause the other. If my brain cannot balance neurotransmitters and I become depressed, my depressive mind will reduce my motivation which will reduce my work performance. Conversely, my work life could be so bad that my brain sinks to a depressive state which manifests itself outside of work. When helping someone (or yourself) in situations like these, it is important to consider both the situation and the neuropsychology - and professional (psychiatrists, therapists, and career counselors) help is a good way to do it. 

Identifying the Issue

There are several things that can be happening when someone shows symptoms of burnout. They can happen individually or all at once. If you notice difficulty with concentrating or completing tasks, a lack of motivation especially to start new tasks or try new things, and a general lack of energy, you may say a person is burned out. The first reaction may be to attempt to find new motivation or to just take a break (and these help) but the layers beneath burnout may require fixing several things at once. Burnout, stress, anxiety, situational depression, and clinical depression all have ways of feeding each other.

Stress vs. Burnout

The first determination to make is between stress and burnout. They have different ways of presenting themselves and they require different kinds of help. Generally speaking, stress is the result of deadlines, pressure, and demands. Burnout is more of a feeling of hopelessness, apathy, and despair. Stress symptoms are physical and manifest as blood pressure, heart rate, headaches, and such. Burnout symptoms are more emotional and manifest as hopelessness, despair, and detachment. A stressed person often feels they can fix it themselves if they work hard enough, but a burned out person will see their problems as a permanent part of their job. 

Burnout vs Depression

Symptoms of burnout and depression manifest from both clinical depression and from what I call “occupational fatigue.”  That is not a medical term, but it does help differentiate the two. Occupational fatigue is specific and exclusive to work. The person simply has less energy to express interest in their job, company, team, or accomplishments. It could be due to a lack of motivation, team harmony, or goals. A person who is starting the road to burnout will likely just be tired of their job or surroundings and that is the easiest and fastest thing to treat. A change in duties, environment, team, or even employer can refresh someone who is dealing with occupational fatigue but it requires more patience and attention when it becomes pervasive and turns into depression.

Situational vs Clinical Depression

Major (clinical) depression, however, IS a medical term. It is a mood disorder explicitly outlined in the DSM with key symptoms (sadness, guilt, diminished ability to feel pleasure, sleep problems, and more) and has a well-established battery of psychological and medical treatments available. The non-medical term I use, "Situational depression" is what I call it when a depressed mood is less pervasive and long-lasting. Missing out on a promotion, getting a tiny raise, or having a big project fail can cause all the symptoms of depression, including symptoms you take home with you like insomnia and fatigue. However, clinical depression rarely has a single identifiable marker that triggers the condition. Another change in circumstances (a new project, a new path to advancement, or a new job) can clear up situational depression before it grows into a long-term, pervasive depressed state. Clinical depression is best treated with a psychiatrist who can provide both the medical and the psychological tools to cope and recover.

What can I do?

The information above is more useful to the individual employee who feels the symptoms of burnout. As a co-worker, HR rep, or manager, it will naturally be far more difficult to determine exactly which and how many states the employee is facing.

Not Everyone Needs A Solution

As an engineer in the DevOps world, I am accustomed to trying to solve a problem as soon as someone presents it to me. This person is talking to me because there is something wrong that may be in my power to fix, so my brain starts going down all the paths to the solution.

Feelings are not an engineering problem, though. Sometimes a person may approach you and talk about stress and anxiety just for validation, empathy, or venting. In this case, it's OK to ask directly if they're looking for sympathy or looking for actual helpful advice. In a work situation, sometimes all that is needed is someone to take your side and say "Yes, I agree that this sucks" in a bad situation. That way, the individual who is reaching out knows that the job may be difficult, but they are not alone in their feelings and are not crazy for being upset at a justifiably upsetting situation.

Privacy and Policy

There may be company policy and medical privacy concerns that will prevent you from looking too deeply into these matters, so it's best to check for HR policies before asking deep questions. If you have a co-worker who is showing symptoms of burnout, make sure to enter the conversation with a work focus. Talk about projects, schedules, on-call rotation, or goals and what changes they would make to the environment. If they volunteer outside information (like a bad medical diagnosis, family problems, or personal problems,) be as sympathetic as you can without crossing the borders of medical privacy or company policy. When possible, coordinate between the manager and HR to introduce/remind the employee of the resources available to them provided by the company like medical benefits and anonymous crisis/therapy call centers. 

Psychiatry and Medication

If an employee is seeing a psychiatrist and is put on psychiatric medication, saying "Take any time you need to deal with doctor appointments or side effects" is a great show of support, but "Did you see your doctor recently?" or "Did you remember to take your medication?" is both patronizing and infringing on medical privacy. Also remember that most psychiatric medications have a number of unpleasant side-effects and it may be valuable to expand work-from-home policies or other helpful programs. 

There is a big stigma around psychiatric diagnosis and especially medication. Highly intelligent people can still think a psychiatric problem is "a problem with how I think" and therefore "I can think my way out of it." Additionally, people who believe they are intelligent problem solvers may come up with some rationalization that will "explain" their feelings without ever having them examined by anyone else - much less a trained psychiatrist or psychologist. I thought exactly that way for a very long time until I realized that no amount of logic can change the balance of neurotransmitters in the brain. If a person doesn't have the ability (either temporarily or permanently) to properly regulate the happiness chemicals, that person will never feel happiness regardless of how good life is to them. Also, do not self-diagnose and do not self-medicate or self-treat outside of the care of a trained doctor, counselor, or therapist. You may do more harm than good.

The best argument I heard about psychiatric medication is one I credit to my mother: Patients with heart disease can help their situation through diet, exercise, and lifestyle changes but the problem is still medical and the only way to be TRULY SAFE is with medical treatment. The same is true with psychiatry. Medication can help alleviate the the hopelessness, lethargy, apathy, and guilt long enough for the patient to develop the habits needed to feel happiness again. Psychiatric medication doesn't cause happiness, but it can help chip at the walls that keep someone stuck in misery.

There are also plenty of good options for treatment that does not involve medication. I do not have any personal experience with neurofeedback, TMS, or other non-chemical therapy methods, but thee are a number of studies showing efficacy in those options. If one psychiatrist tells you the ONLY way to explore treatment is through medication or only through talk therapy, you have a choice and can talk to other psychiatrists as well. [Paragraph added from feedback - thanks Jared]  

Remember that the very best to do in the workplace is to remove the stigma or shame surrounding psychiatric care. Jokes about "being crazy" and "getting your head shrunk" may be met with laughs on the outside, but can tear someone up inside.

Employer Resources

Here is a short list of helpful resources that may be available through an employer that can help with burnout, depression, and anxiety:

  • Crisis or counseling hotlines.
  • Personal/sick days or work-from-home policies.
  • Career development counseling.
  • One-on-one manager-employee meetings.
  • Focus rooms (places where an employee can work in relative quiet, privacy, or without distraction - especially valuable in workplaces with those awful "open floor plans" that are so popular.)
  • Employee-led leadership exercises. (Giving an employee domain over a project is very empowering) 

You Can Only Do So Much

While a job in the DevOps world is full of both empathy and problem-solving, there is one crucial fact to remember: The only person responsible for an employee's happiness is that individual. A depressed, anxious, burned out, or stressed person who refuses to acknowledge it, seek help, or take advantage of helpful resources ultimately cannot be the responsibility of anybody else. There are people who will sit on a problem forever without attempting to fix it. 

As a teammate, your job is to offer sympathy, assistance, and resources but NOT take full responsibility for someone else's emotional state. If you throw a life vest to a person drowning in a river and they refuse to put it on, you cannot be blamed if they eventually drown. Likewise, if someone throws you a life vest and you do not try it on, you shouldn't be surprised if you eventually end up in water that's too deep.

On Suicide

There have been a number of suicides in this industry and there has been some worry that it is a result of the high-stress, high-results, fast-paced nature of the industry. While continued application of stress can lead to anxiety or depression, it is important to realize that suicide is NOT inevitable and is always an exceptional circumstance. 

Suicide has touched my life several times and I spent a lot of time reading and thinking about the subject. I will go against the flow of most of psychology and medicine (they are not my fields, after all) and say that I believe there are some suicides that happen which are entirely understandable and justifiable. For example: If a beloved grandparent spent over sixty years married to one woman, raised a big family, suddenly lost his life partner, and decides to end his own life, we can be saddened by it but we should not be angry or blame ourselves. Suicide happens when the pain of continued living entirely eclipses fear of death or possibility of pleasure in the future. 

It is extremely important to remind yourself that a person who is determined to suicide will find a way to do it. Short of locking them in a padded room tied to a gurney, there is nothing you can do to stop a person absolutely determined to take their own life. They are NOT thinking rationally so any rational approach you may possibly have offered will have been dismissed. 

The cliche "suicide is a permanent solution to a temporary problem" is often, but not always, true. Do everything you can to help someone and be especially sensitive to hopeless phrases like "I just can't do this anymore" or "This will never get better." If you can, try to show them how they CAN keep going and how it WILL get better. However, if they decide to leave permanently, do not assign blame. Especially not to yourself. I will repeat this, though: If you feel you or anyone is in danger of self-harm or harming others, call your emergency services (911 in the US) right away and they can find help.

Further Reading

I intentionally did not reference many academic studies or therapeutic guides. I wrote about what I know: what causes burnout, how burnout is different from other conditions that exhibit the same symptoms, and what we can hope to do if we face it in a DevOps team. I did not cover a lot of points in this post like:

  • How do psychiatrists treat depression and anxiety?
  • What can I expect from psychiatric care for depression or anxiety?
  • How do career counselors help people cope with burnout?
  • What are the medical and privacy laws that cover psychiatric treatment?
  • How does a team cope with a single individual who is facing burnout without having the feeling spread across the team?

Those are questions better suited for the doctors, lawyers, and managers who are trained to answer such questions. I will instead close with what I DO know:

  • If you ignore stress and depression, it will probably get worse.
  • There is nothing wrong with feeling stressed or depressed and seeking help is a POSITIVE move.
  • Be sympathetic, honest and open with your team, be fair to them, and be true to yourself.

Minor Update: Site Overhaul

With the help of Monroe, thoughtfix.com has been entirely redesigned. With the help of Squarespace, all previous content has been ported over to this new design. I love it. Thank you! 

I have been spending time working on an Openbeam Kossel Pro 3D printer and, thanks to the forums, we got it working happily. I also have been immersing myself in more PC gaming (you can guess my Steam ID) and building machines capable of that. I look forward to hacking SteamOS when it is ready. Get to it, Valve!

I uploaded the Kossel Pro build log to my Galleries up there. Finally: I left San Francisco and moved about 20 miles down the Bay. It was cost prohibitive to live in the city for even one more year. Tech companies need to stop opening offices downtown (Uber, Twitter, Reddit) unless they pay people a proportionally higher salary to afford living there.



Maker Faire Bay Area photo album

Long overdue update

I have not been managing this nearly as much as I should, so here' a quick bullet-point update on my projects at the conclusion of Maker Faire 2014:


  • New job, new home! I moved to downtown San Francisco to accept a job there. My apartment is much smaller (naturally - it's SF) so I don't have as much space for both robotics and 3D printing. I do have enough space to switch between the two.
  • The Printrbot Plus v2 is fun, but it's getting an overhaul in parts - more metal for structural stability and more rigidity for speed, plus a transition from 3mm to 1.75mm filament and an aluminum extruder.
  • Someone left behind a Botiful robot when changing offices. I contacted Claire, the designer, to see if anyone lost their Kickstarter rewards but she had no way of knowing. With her help, I got it working again and it's a lot of fun.
  • I am giving up on drones as a hobby as long as I live in SF. It's too windy and crowded and I don't want to hurt the drone or a person.
  • My favorite update: I backed and received Super Awesome Sylvia and EMSL's WaterColorBot and have truly wicked plans for expanding on the hardware. I have to thank Lenore and Windell from Evil Mad Scientist Labs for the inspiration and support.

That's all for now. 


Sparkfun ITG-3200 Gyroscope Example Arduino Code

The official documentation and example code on Sparkfun's Site is very slightly broken and not updated for Arduino 1.0. I fixed it and sent it to them. Also posting it here:

Original author: 
Basic Example Sketch for the ITG-3200 (http://www.sparkfun.com/products/9801)
SparkFun Electronics 2011
Ryan Owens
This code is public domain buy you buy me a beer if you use this and we meet someday (Beerware license).
Updated some variables and Arduino 1.0 compatibility:
Daniel Gentleman
Will take coffee in place of beer.
To use this example code, attach:
Arduino  :  ITG-3200 Breakout
3.3V  :  VDD
3.3V  :  VIO
GND   :  GND
SDA   :  A4
SCL   :  A5
Load the sketch and open the serial window at 9600 bps. Arduino will output the raw X,Y and Z axis data being read from the gyroscope.
//The Wire library is used for I2C communication
#include <Wire.h>
//This is a list of registers in the ITG-3200. Registers are parameters that determine how the sensor will behave, or they can hold data that represent the
//sensors current status.
//To learn more about the registers on the ITG-3200, download and read the datasheet.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;
//This is a list of settings that can be loaded into the registers.
//DLPF, Full Scale Register Bits
//FS_SEL must be set to 3 for proper operation
//Set DLPF_CFG to 3 for 1kHz Fint and 42 Hz Low Pass Filter
char DLPF_CFG_0 = (1<<0);
char DLPF_CFG_1 = (1<<1);
char DLPF_CFG_2 = (1<<2);
char DLPF_FS_SEL_0 = (1<<3);
char DLPF_FS_SEL_1 = (1<<4);
//I2C devices each have an address. The address is defined in the datasheet for the device. The ITG-3200 breakout board can have different address depending on how
//the jumper on top of the board is configured. By default, the jumper is connected to the VDD pin. When the jumper is connected to the VDD pin the I2C address
//is 0x69.
char itgAddress = 0x69;
//In the setup section of the sketch the serial port will be configured, the i2c communication will be initialized, and the itg-3200 will be configured.
void setup()
  //Create a serial connection using a 9600bps baud rate.
  //Initialize the I2C communication. This will set the Arduino up as the 'Master' device.
  //Read the WHO_AM_I register and print the result
  char id=0; 
  id = itgRead(itgAddress, 0x00);  
  Serial.print("ID: ");
  Serial.println(id, HEX);
  //Configure the gyroscope
  //Set the gyroscope scale for the outputs to +/-2000 degrees per second
  itgWrite(itgAddress, DLPF_FS, (DLPF_FS_SEL_0|DLPF_FS_SEL_1|DLPF_CFG_0));
  //Set the sample rate to 100 hz
  itgWrite(itgAddress, SMPLRT_DIV, 9);
//The loop section of the sketch will read the X,Y and Z output rates from the gyroscope and output them in the Serial Terminal
void loop()
  //Create variables to hold the output rates.
  int xRate, yRate, zRate;
  //Read the x,y and z output rates from the gyroscope.
  xRate = readX();
  yRate = readY();
  zRate = readZ();
  //Print the output rates to the terminal, seperated by a TAB character.
  Serial.print(xRate);  //fixed variables here from original code. DG.
  //Wait 10ms before reading the values again. (Remember, the output rate was set to 100hz and 1reading per 10ms = 100hz.)
//This function will write a value to a register on the itg-3200.
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be written to.
//  char data: The value to be written to the specified register.
void itgWrite(char address, char registerAddress, char data)
  //Initiate a communication sequence with the desired i2c device
  //Tell the I2C address which register we are writing to
  //Send the value to write to the specified register
  //End the communication sequence
//This function will read the data from a specified register on the ITG-3200 and return the value.
//  char address: The I2C address of the sensor. For the ITG-3200 breakout the address is 0x69.
//  char registerAddress: The address of the register on the sensor that should be read
//  unsigned char: The value currently residing in the specified register
unsigned char itgRead(char address, char registerAddress)
  //This variable will hold the contents read from the i2c device.
  unsigned char data=0;
  //Send the register address to be read.
  //Send the Register Address
  //End the communication sequence.
  //Ask the I2C device for data
  Wire.requestFrom(address, 1);
  //Wait for a response from the I2C device
    //Save the data sent from the I2C device
    data = Wire.read();
  //End the communication sequence.
  //Return the data read during the operation
  return data;
//This function is used to read the X-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int xRate = readX();
int readX(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_XOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_XOUT_L);  
  return data;
//This function is used to read the Y-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int yRate = readY();
int readY(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_YOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_YOUT_L);  
  return data;
//This function is used to read the Z-Axis rate of the gyroscope. The function returns the ADC value from the Gyroscope
//NOTE: This value is NOT in degrees per second. 
//Usage: int zRate = readZ();
int readZ(void)
  int data=0;
  data = itgRead(itgAddress, GYRO_ZOUT_H)<<8;
  data |= itgRead(itgAddress, GYRO_ZOUT_L);  
  return data;


Arduino, BOE Shield, PING, and a servo

The video above is in two parts: first with a crawler kit and then with wheels. Switching back to wheels required a code modification to change the time it takes to turn. 
All the parts in the video were released for the original STAMP/Propeller chips, but the code below will get you off and running on the Arduino shield. Only digital pins 10, 11, 12, and 13 are used, so any shield that does not require those pins is available for use. 
// BOE Shield code from "Robotics with the BOE Bot"
// Roaming With Whiskers source, modified to use a PING)))
// sensor on the PING))) servo bracket.
// Using code from the Ping))) example sketch.
#include <Servo.h>                           // Include servo library
Servo servoLeft;                             // Declare left, right and Ping))) servos
Servo servoRight;
Servo PingServo;
int minSafeDist = 11 ;                        // Minimum distance in inches
int pingPin = 10;                             // PING input on 10 so the last servo port is used.
int centerDist, leftDist, rightDist;          // Define distance variables
long duration, inches, cm;                    // Define variables for Ping)))
void setup()                                 // Built-in initialization block
  tone(4, 3000, 1000);                       // Play tone for 1 second
  delay(1000);                               // Delay to finish tone
  servoLeft.attach(13);                      // Attach left signal to pin 13 
  servoRight.attach(12);                     // Attach right signal to pin 12
void loop(){
  if(inches >= minSafeDist) /* If the inches in front of an object is greater than or equal to the minimum safe distance (11 inches), react*/
    forward (121); //Go Forward
    delay(110); // Wait 0.11 seconds
  else // If not:
    LookAround(); // Check your surroundings for best route
    if(rightDist > leftDist) // If the right distance is greater than the left distance , turn right
      turnRight (250); // Turn Right      
    else if (leftDist > rightDist) // If the left distance is greater than the right distance , turn left
      turnLeft (250); // Turn Left
      backward (250); // Go Backward
    delay (250);
void forward(int time)                       // Forward function
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
void turnLeft(int time)                      // Left turn function
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1300);        // Right wheel clockwise
  delay(time);                               // Maneuver for time ms
void turnRight(int time)                     // Right turn function
  servoLeft.writeMicroseconds(1700);         // Left wheel counterclockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
void backward(int time)                      // Backward function
  servoLeft.writeMicroseconds(1300);         // Left wheel clockwise
  servoRight.writeMicroseconds(1700);        // Right wheel counterclockwise
  delay(time);                               // Maneuver for time ms
unsigned long ping() {
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW); //Send a low pulse
  delayMicroseconds(2); // wait for two microseconds
  digitalWrite(pingPin, HIGH); // Send a high pulse
  delayMicroseconds(5); // wait for 5 micro seconds
  digitalWrite(pingPin, LOW); // send a low pulse
  pinMode(pingPin,INPUT); // switch the Pingpin to input
  duration = pulseIn(pingPin, HIGH); //listen for echo
  /*Convert micro seconds to Inches
  cm = microsecondsToCentimeters(duration);
  inches = microsecondsToInches(duration);
long microsecondsToInches(long microseconds) // converts time to a distance
  return microseconds / 74 / 2;
long microsecondsToCentimeters(long microseconds) // converts time to a distance
  return microseconds / 29 / 2;
void LookAhead() {
  PingServo.write(90);// angle to look forward
  delay(175); // wait 0.175 seconds
void LookAround(){
  PingServo.write(20); // 20° angle
  delay(320); // wait 0.32 seconds
  rightDist = inches; //get the right distance
  PingServo.write(160); // look to the other side
  delay(620); // wait 0.62 seconds
  leftDist = inches; // get the left distance
  PingServo.write(90); // 90° angle
  delay(275); // wait 0.275 seconds


BOE Shield Crawler Kit notes/video

The crawler kit was a big pain to build, but it looks cool! It is essential to use the correct screws and nuts exactly as described in the instructions. Long screws and lock nuts are at the "knees," tapping screws in the pivots, and a nice comfortable drilled hole for the servo horn. 

CODE! The robot is functionally identical to the standard "navigation with whiskers" bot but the whiskers are higher from the ground and bounce up and down. In general - it is far less reliable. Any code included for turns should have durations about four to six times longer to allow for the added turning time of the crawler.

Some tips:


  • If you break your servo horn while cutting/drilling the extra space for the bolt, don't worry too much: The other three spokes will do just fine. If you completely break your servo horn, the horns that came with the original BOE Shield kit work fine.
  • Don't let the diagram on the middle legs confuse you - they're both assembled the same way.
  • Double check your washers before tightening the bolts on the middle legs. The one closest to the servo horn is a 1/8" spacer and looks twice as thick as the other nylon washers.
  • Needle-nose pliers are very useful in tightening those lock nuts - but don't over-tighten them!A good measure its to tighten them just enough to allow the friction of a leg to keep it from spinning downward with gravity, then slightly loosen it from there.
  • My crawler kit was four washers short. I easily found matching nylon washers at Lowes (Hillman #6 nylon flat washers)

BOE Shield Whisker Kit

This video is a direct follow-up on my last post. It just shows the next step of growth on the BOE Bot.

Some notes on assembly:


It's VERY difficult to use the nylon spacer near the mounting header by the AREF pin. I skipped using the spacer and just used the screw and nut - tightening it until it felt snug.

Between ShieldSetup and building your robot, it actually IS important to do the servo centering. Both of the servos I got were not centered.

The 1" aluminum standoffs and screws aren't attached to the shield when it is shipped. The instructions are there for people who followed the introduction course and mounted the shield before the 
In the same bag, there are two lengths of screws and all fit the standoffs. USE THE SHORT SCREWS FOR THE STANDOFFS. The long screws are needed to mount the servos.

Tires: Annoying!

Spare parts: All bolts are used. Two spare "tire" rubber bands are included. Once you assemble the base kit, you'll have two long screws, two short risers, and two nylon washers left over as well. Those are used for the whisker kit.

Example sketch notes:
Many of the example sketches run all the code in void setup() so they only run once and stop. This means the servo test code will only run once. If your power switch is in the wrong position and you start the test, hit the reset button and see if it runs.

Parallax BOE Shield for Arduino: First Look

I'm a big fan of Parallax and adafruit industries, so was glad to learn that they are now stocking the Parallax BOE Shield for Arduino. I already owned this kit but have yet to have time to play with it. The video above is an unboxing of the BOE Shield, PING))) sensor mounting bracket, and crawler kit. 
The original Parallax BOE-Bot uses Propeller controller and is very good for learning robotics in that environment. The lessons, documentation, and examples are quite detailed. With a focus on education, Parallax wisely decided to expand this platform into Arduino territory. The only "required" pins for the shield are two of 10, 11, 12, and 13. You can choose which two in your Arduino code. The rest can be used with your normal stackable Arduino shields.
To get a general idea of the BOE Shield and completed robot in action, take a look at adafruit's new product announcement.
Here's a photo of the crawler kit sitting on an original BOE bot (borrowed from Parallax's site) that I intend to use with the BOE Shield.
I'll be posting all my source code and a bunch of pictures or videos, but it will all pale in comparison to the online book from Parallax.
Stay tuned for more!


R2-D2 Laser Robot for Cats

This is an expanded modification for the Laser ToyBot for Cats to fit into an R2-D2 toy. The entire project can be built with significantly less work without using the R2-D2, but the astromech droid had a lot more flair. First: How to make it work from scratch:

The first revision was just an Ardweeny on a proto board with some hot-glue attaching the continuous rotation servo horn to a project box. It spins in horizontal circles, randomly changing directions while also randomly changing vertical angle. The vertical servo must be "tuned" so it is consistently pointing toward the ground unless you enjoy having your cats climb the walls. 

Simple parts:

  1. Ardweeny (Maker Shed)
  2. Adafruit 1/2 Size Perma-Proto Board (adafruit)
  3. Micro Servo and perhaps some 10uF capacitors to clean up the noise (adafruit)
  4. Sparkfun TTL Laser and 10k resistor (Sparkfun) 
  5. Continuous Rotation Servo (adafruit)
  6. 3xAAA battery holder (adafruit)

Advanced/Optional parts:

  1. RobotShop pan kit for either Futaba or Hitec servos. I went with the Hitec version and modified a Hitec HS-422 servo for continuous rotation. Futaba continuous rotation servos are more widely available without modification, but the Futaba pan kit is more expensive. The servo I linked above is a Futaba servo.
  2. R2-D2 model. I used a Diamond Select bank I found on Amazon but can't find it anymore.
  3. Shape Lock molding plastic. (Maker Shed)
  4. On-Off button and LED. This beauty from adafruit does both

Simple assembly:

In my non-Droid version, I simply sandwiched the servos between the proto board and the battery holder then used hot glue to affix the continuous rotation servo to a project enclosure. It worked fine, but was not sturdy. The switch to the Perma-Proto board was ideal as shown here:

Pin assignment:

  • Vertical (standard) servo: 10
  • Horizontal (continuous rotation) servo: 9
  • Laser diode: 8  (The diode is TTL controlled and uses a 10k resistor to ground)
  • Power LED: 7

That's all that is needed to get a basic laser toy running. Fitting it into the R2-D2 robot was a bit more challenging. I needed to find a way to allow the entire R2-D2 head to spin freely without tangling wires and I didn't have a slip ring (but adafruit does now) so I decided to make the entire electronic device rotate. Finding the DDP155 Pan System from RobotShop and mounting it upside down solved that for me. I screwed in a few risers to the rotating plate to lift it higher into the droid model. 


When working with ShapeLock, be aware that the hot plastic will bond to other plastics. To get a very close form, insulate other plastic areas with aluminum foil until the cooling completes. ShapeLock can be cut with a Dremel rotary tool with a plastic or wood cutting bit at 5-8k RPM. Going over 10k causes the plastic to melt. USE SAFETY GLASSES when using a rotary tool. Little bits of white plastic in the eye are not fun.

The most difficult part of the R2-D2 enclosure was the centering and balancing of the head on the RobotShop pan kit. This took several tries. Thankfully ShapeLock can simply be melted down and re-molded. 

That's it for the construction. The rest is just source code. Enjoy!


/* Arduino laser cat toy
 2012 Daniel Gentleman
 Creative Commons Attribution license
 Laser diode attached to a standard servo for vertical movement
 Continuous rotation servo for horizontal spinning
 Power LED (optional) 
#include <Servo.h> 
Servo myservoh;  // Horizontal servo - continuous rotation
Servo myservov; // Vertical servo - standard 
unsigned int duration = 0;
int lasttime1 = 0;
int lasttime2 = 0;
int randstart = 0;
int randend = 0;
int pos = 0;
int laser = 8; // TTL laser diode on pin 8
int vpos = 80; 
int powerLed = 7; // Power LED on pin 7
void setup()
  myservoh.attach(9); // Continuous rotation servo on pin 9
  myservov.attach(10); // Standard servo on pin 8
  pinMode(laser, OUTPUT);
  pinMode(powerLed, OUTPUT);
  digitalWrite(laser, LOW);  // Turn ON the laser 
  digitalWrite(powerLed, HIGH); // Turn ON the power LED
void loop()
  int vaxis = random(50,120); // Range of vertical movement (50-120 here)
  lasttime1 = millis();
  randstart =  random(200, 19990); // Tune these for your preferred random behavior
  randend =  random(2000, 2400);
  while(pos <= randend) // Random horizontal spinning 
    pos += 1;
  vaxis = random(70,100);
  myservov.write(vaxis); // Random vertical movement
  duration = millis() - lasttime1;
  lasttime2 = millis();
  while(pos >= randstart)
  vaxis = random(70,100);
  duration = millis() - lasttime2;
  duration = millis() - lasttime1;


Sparkfun RGB LED and RGB Light Sensor

I can't quite figure this one out: it's VERY delicate and I can't get consistant color results with the built-on LED on or off. I know if it gets a UV light, it shows a lot of purple and if it gets hit with a red laser it maxes out the red LED. Anyhow... Video and code! 



Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sending
PWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012
Inherited OSHW license.
Original comments below.
An Arduino code example for interfacing with the 
HDJD-S822-QR999 Color Sensor.  Put an object in front of the
sensor and look at the serial monitor to see the values the sensor
is reading.  Scaling factors and gains may have to be adjusted
for your application.
by: Jordan McConnell
 SparkFun Electronics
 created on: 1/24/12
 license: OSHW 1.0, http://freedomdefined.org/OSHW
Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).
Connect the led pin to digital 13.
Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.
// Define pins
const int ledpin = 13;
const int GSR1 = 12;
const int GSR0 = 11;
const int GSG1 = 10;
const int GSG0 = 9;
const int GSB1 = 8;
const int GSB0 = 7;
const int redLed = 3;
const int greenLed = 5;
const int blueLed = 6;
int redpin = A0;
int greenpin = A1;
int bluepin = A2;
// Sensor read values
int red = 0;
int green = 0;
int blue = 0;
int redBright = 0;
int greenBright = 0;
int blueBright = 0;
void setup() 
  pinMode(ledpin, OUTPUT);
  pinMode(GSR1, OUTPUT);
  pinMode(GSR0, OUTPUT);
  pinMode(GSG1, OUTPUT);
  pinMode(GSG0, OUTPUT);
  pinMode(GSB1, OUTPUT);
  pinMode(GSB0, OUTPUT);
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  // Turn on the LED
  digitalWrite(ledpin, LOW);
  // Set the gain of each sensor
  digitalWrite(GSR1, LOW);
  digitalWrite(GSR0, LOW);
  digitalWrite(GSG1, LOW);
  digitalWrite(GSG0, LOW);
  digitalWrite(GSB1, LOW);
  digitalWrite(GSB0, LOW);
void loop() 
  // Read sensors
  // On page 7 of the datasheet, there is a graph of the 
  // spectral responsivity of the chip.  Scaling factors were
  // selected based on this graph so that the gain of each 
  // color is closer to being equal
  red = analogRead(redpin) * 10;
  green = analogRead(greenpin) * 14;
  blue = analogRead(bluepin) * 17;
  redBright = red/10;
  greenBright = green/10;
  blueBright = blue/10;
  // Print values to the serial monitor
  Serial.print("Red: ");
  Serial.print(red, DEC);
  analogWrite(redLed, redBright);
  Serial.print("\t\tGreen: ");
  Serial.print(green, DEC);
  analogWrite(greenLed, greenBright);
  Serial.print("\tBlue: ");
  Serial.println(blue, DEC);
  analogWrite(blueLed, blueBright);
/*Expanded to use the Sparkfun RGB LED on pins 3, 5, and 6, sendingPWM signals as 1/10 of the result. YouTube video of this in action at
Use of the RGB LED changes added by thoughtfix 2/2012Inherited OSHW license.Original comments below.*/
/*An Arduino code example for interfacing with the HDJD-S822-QR999 Color Sensor.  Put an object in front of thesensor and look at the serial monitor to see the values the sensoris reading.  Scaling factors and gains may have to be adjustedfor your application.
by: Jordan McConnell SparkFun Electronics created on: 1/24/12 license: OSHW 1.0, http://freedomdefined.org/OSHW Connect the gain pins of the sensor to digital pins 7 - 12 (or ground).Connect the led pin to digital 13.Connect Vr to analog 0, Vg to analog 1, and Vb to analog 2.*/

// Define pinsconst int ledpin = 13;const int GSR1 = 12;const int GSR0 = 11;const int GSG1 = 10;const int GSG0 = 9;const int GSB1 = 8;const int GSB0 = 7;const int redLed = 3;const int greenLed = 5;const int blueLed = 6;
int redpin = A0;int greenpin = A1;int bluepin = A2;
// Sensor read valuesint red = 0;int green = 0;int blue = 0;int redBright = 0;int greenBright = 0;int blueBright = 0;
void setup() {  Serial.begin(9600);
  pinMode(ledpin, OUTPUT);  pinMode(GSR1, OUTPUT);  pinMode(GSR0, OUTPUT);  pinMode(GSG1, OUTPUT);  pinMode(GSG0, OUTPUT);  pinMode(GSB1, OUTPUT);  pinMode(GSB0, OUTPUT);  pinMode(redLed, OUTPUT);  pinMode(greenLed, OUTPUT);  pinMode(blueLed, OUTPUT);
  // Turn on the LED  digitalWrite(ledpin, LOW);    // Set the gain of each sensor  digitalWrite(GSR1, LOW);  digitalWrite(GSR0, LOW);  digitalWrite(GSG1, LOW);  digitalWrite(GSG0, LOW);  digitalWrite(GSB1, LOW);  digitalWrite(GSB0, LOW);}
void loop() {    // Read sensors  // On page 7 of the datasheet, there is a graph of the   // spectral responsivity of the chip.  Scaling factors were  // selected based on this graph so that the gain of each   // color is closer to being equal  red = analogRead(redpin) * 10;  green = analogRead(greenpin) * 14;  blue = analogRead(bluepin) * 17;  redBright = red/10;  greenBright = green/10;  blueBright = blue/10;
  // Print values to the serial monitor  Serial.print("Red: ");  Serial.print(red, DEC);  analogWrite(redLed, redBright);  Serial.print("\t\tGreen: ");  Serial.print(green, DEC);  analogWrite(greenLed, greenBright);  Serial.print("\tBlue: ");  Serial.println(blue, DEC);  analogWrite(blueLed, blueBright);  delay(20);}