Instructions for building a self levelling hand for the InMoov robot ( using slightly adjusted InMoov parts, an orientation sensor, an arduino nano and an additional servo.

Hardware 1


This is the part responsible for the magic. It is a joy to have such an easy to use accurate device available for only ~30€.

Hardware 2


For another ~25€ (2€ if ordered in china) you can get an arduino nano for reading the sensor data and control the rotation and bending servos.

Hardware 3


I use this servo for rotation and bending movement (Hobbyking). Specs are (6V) .15 sec / 60 deg. and 30 and did cost 28€ each. They are digital and do a good job. Do not expect the hand to carry heavy stuff however, angles are small and the strings far off of being a human tendon.

To bend the wrist


On this schema we have the hand to the left, the wrist to the right. In order to minimize friction the strings move over rolls on 3 redirection axis's. I used nails as axis and spacers on the nails to avoid sharp turns. The connections to the hand have a slight X-offset allowing 2 different spacers on the middle axis as they rotate in different directions when moving. I also added a honk to the hand to get a better point for pulling the hand up/down.

The Modified Hand


Here you can see the slightly offset honks to provide a better point for creating a bending movement. You can also see that I have rearranged the channels as I needed an area in the center to fix the strings. There is also a slighly larger middle channel for the thumb (middle hole to the right) as my sensor wires (4) need to pass through there.

Wrist to Hand Connector


This is the adjusted Rotawrist3 providing holes for the redirection axis and a reduced turn axis holder to avoid collisions with the hand when bending.

180 Degree Wrist Rotation


I spent quite some time on making the wrist rotate 180 degrees. Had a kind of working solution with the existing gears and a winch servo. However the winch servo just moved too slow and far and it did not result in a steady hand control. So I swiched to gears that allow a 180 degree wrist roatation with a 180 degree wrist servo. I do use thin strings (Marowil, 0.58 mm, ~50 kg) so I was able to squeeze the holes into the reduced size gear. The yellow holes are the ones for the bending strings. They have an X-offset to each other and make sure you use the correct hole for upper/lower string.

Reduced Gear Size


Needed to adjust Rotawrist2 for the smaller middle gear part. My servo with the gear on top also did not fit so I added 1 mm to the heigt of the part.



I needed 2 more holes for my bending strings. I also removed parts that prevented my servo to sink completely into the part.



At the bottom I have added a connection block to allow for a fixing screw with the lower forearm.



The forearm has pillars for the bending servo. I decided to have this servo upright to get a more direct path for the strings when passing through the wrist gear.



The pulley for the bending servo has an offset rotation axis because the strings do not move equal distances when the hand bends. As my math is not the best I spent a lot of time trying to find the right dimension and point of rotatioin for the pulley. Finally Excel Solver optimized it for me.

Tool for Redesigning Parts

All my adjustments to the parts have been made with OpenScad. I can load .stl files into my scripts and then modify the part in OpenScad

Hand Cover


As the cover needed to be shortened to allow the bending movement it would have destroyed the InMoov inprint on it. I asked Gaël to make me a cover with a replaced inprint and he helped me out almost immediately (also complaining that it was a more time consuming task then he expected it to be).

Hiding the Sensor and Fixing Screws


Made some room for the sensor and screws inside the hand cover.

Programming the Arduino Nano

The adafruit bno055 comes with example code how to work with the sensor. My additions were rather easy.

**Some definitions for the servo controlling

#define PIN_COMMAND (8) int pitchServoPin = 9; int rollServoPin = 10; int FeedbackPin = 13; /* interne gelbe LED */

Servo rollServo; // create servo object to control turning movement Servo pitchServo; // create servo object to control bending movement

int CommandMode; int ModeBefore;

int rollValue = 1500; // variable to store the servo position int rollMin = 600; int rollMax = 2400; int rollRead; // normalized roll value int rollKorr = 5;

int pitchValue = 1500; // variable to store the target servo position int pitchMin = 600; int pitchMax = 2400; int pitchRead; // calibrated pitch value int pitchKorr = -1;

/* Set the delay between fresh samples */ #define BNO055SAMPLERATEDELAY_MS (20)

**... initialization of the pin used to activate the self control pinMode(PINCOMMAND, INPUTPULLUP); // the self-control is activated with pin in high state (1) ModeBefore = LOW;

... and the additions in the loop

/* Check for activated Command pin */ CommandMode = digitalRead(PIN_COMMAND);

if (CommandMode == HIGH) {

if (ModeBefore == LOW) {
    rollServo.attach(rollServoPin);  // attaches the servo on pin 10 to the servo object
    pitchServo.attach(pitchServoPin);  // attaches the servo on pin  9 to the servo object
    ModeBefore = HIGH;
    digitalWrite(FeedbackPin, HIGH);

/* Get a new sensor event */

/* use pitch value to change servo command
pitchRead = event.orientation.y + pitchKorr;

if (abs(pitchRead) > 10) {
  pitchValue = pitchValue + (pitchRead * 5);
} else {
  pitchValue = pitchValue + (pitchRead * 3);

/* limit to min value */    
if (pitchValue > pitchMax) pitchValue = pitchMax;
if (pitchValue < pitchMin) pitchValue = pitchMin;


Serial.print("\tPitch: ");
Serial.print("\t pitchServo target: ");

/* as the sensor is below the hand the goal is to get 180 degree roll 
normalize the value
if (event.orientation.z < 0) rollRead = 360 + event.orientation.z + rollKorr;
if (event.orientation.z >= 0) rollRead = event.orientation.z + rollKorr;
Serial.print("\trollRead: "); Serial.print(rollRead);

rollValue = rollValue - ((rollRead - 180) * 5);

/* do not cross the limits */
if (rollValue > rollMax) rollValue = rollMax;
if (rollValue < rollMin) rollValue = rollMin;

Serial.print("\t rollServo target: ");

/* New line for the next sample */

} else { if (ModeBefore == HIGH) { rollServo.detach(); // detaches the servo on pin 10 to the servo object pitchServo.detach(); // detaches the servo on pin 9 to the servo object ModeBefore = LOW; digitalWrite(FeedbackPin, LOW); } }

/* Wait the specified delay before requesting nex data */ delay(BNO055SAMPLERATEDELAY_MS);

Using MRL to Activate the Self-Levelling

In MRL (the software controlling the whole robot) Alessandro showed me how to control a digital pin in the main Arduino Mega to inform the Arduino Nano about its mode:

get a reference to the arduino to set a digital output pin

arduino = Runtime.getService("i01.right") # get arduino for pin setting keepHorizontalOutPin = 12 keepHorizontal = False arduino.pinMode(keepHorizontalOutPin, Arduino.OUTPUT) #set as output port arduino.digitalWrite(keepHorizontalOutPin, 0) #disable levelling

and a little function to pass control of the wrist to the Arduino Nano

def startSelfLevellingHand(): global keepHorizontal keepHorizontal = True i01.rightHand.wrist.detach(); arduino.digitalWrite(keepHorizontalOutPin, 1) #enable levelling


It was rather easy to create the prototype of the hand, actually adding it to the robot was a huge task. Not only did I spend a lot of time with adjusting, printing, adjusting, printing ... of the modified parts, in general the handling of the strings in the wrist sometimes forced me to a break as my fingers just couldn't handle it any more. There is still room for enhancement, I am planning to adjust the axis that connects the hand as it has a bit too much inpact on the fingers when bending it. Stay tuned and if you actually try to make your own let me know whether I left out something.

The respective author is responsible for articles (snaptips) within this service.

Leave a comment

xYou need to be logged in to leave a comment