DIY hobby servos quadruped robot

Cheap 3D printed 4 legged robot, that almost looks like boston dynamics spot but moves like a newborn.

Public Chat
Similar projects worth following
Being a undergradute in physics and bored of solving paper problems, i decided to solve and apply a real world problems so i started this robotics project in order to introduce my self to control theory, studying its maths and practicing pragramming.
It runs with Raspberry Pi 4 as brain, plus an Arduino Mega for reading/writing of signals of 12 hobby servos and IMU, controlled by a PS3 Dualshock.

General Summary

The code which is mostly written by me, using python3 along with some typical libraries for the task, for now implements a walking loop inside a kinematic model, so you can command a pose to the body, as well as feet position and also velocity and directinal commands for the walking loop. Controlled by a ps3 controller via bluetooth.

Arduino is used for speed up the reading and writing of signals, so in the future i can add other sensor, as well as position feedback... This communication is made via bidirectional Serial Commands, so servo pulses are sent to the arduino and angles on IMU are recived on the Raspberry Pi.

As soon as you see the project, you will notice i'm not using Raspberry Pi, thats becouse as i don't have batteries for now (This will be finished in the following updates), its more comfortable for me to work on the PC, on Raspberry Pi it would work the same.

Last run of the robot:

Code of the robot

Project log index (updated):

  1. Model and code explanation.
    1. The kinematic model.
    2. Step trajectory and Gait planner.
    3. Arduino code.
    4. Raspberry Pi communication interfaces.
  2. Robot experiments.
    1. A simple walking method.
    2. Real robot vs PyBullet simulation.
    3. Hitting the robot.
    4. Quadruped robot meets my cat.

Why building a quadruped robot?

Appart from the interesting control problems that this robot involves, there are lot of interesting tasks this it can carry out and they are beginning to be demonstrated, as we have seen with Spot robot in the 2020 pandemic:

It's obious that there is still lot of work to do, but we are at the time where we can built one of these in our homes and have a very good aproximation of it.

There is a key factor in this robot, it doesn't need roads in orther to operate, so it can reach places that are very hard for a wheeled machine, so these 4-legged robot are ideal for tasks such as surveillance, recognition of areas not passable by vehicles and even rescues in areas with danger of collapse.

Finally, it is clear for now, that my robot isn't able to do those tasks, but for now i am satisfied that the robot wolks stable and who knows if in the future it will be able to bring me a beer from the fridge, just by telling to it: 'dog bring me a beer!'

What problems will you face with this robot?

These legged robot have always amazed me, but it was hard to find easy to understand research, as well as a non-trivial mecanical designs plus complex maths. This makes the project hard to achive good results with DIY resources. So i rolled up my slevees and started reading papers from different investigation groups in the subject.

What my project apport to the maker community?

As this project is multidiciplinary, appart from designing my own version of the robot, i focused on its maths, solving different problems related with the movement of the robot, making a very looking forward model which only implements the maths necessary to run the robot, showing how every equation is related with the real robot and givin a general view of it.

This is not the most robust way of building a model, as in real world robots there are lot of additional maths methods in order to pulish the behaviour of the robot, for example, adding interpolation methods would make the robot performs smoother or building an state stimator + filter (kalman state stimator) would let you do very preccise meassurements on the robot and make its movements even more natural.

Visual scheme of electronics and model.

As you can see in the scheme, in this setup i use one bulk converter por 3 servos, with 4 bulk converters in total. This is because each servo drains up to 4A peak.

NOTE: This would not be a rigorous way of wiring, it is just a drawing.

Robot Update (JUL 2020)

  • Finally the new version has been released, in the instruction section you can check how the robot was built, plus building details and all the STL files used are in the file section.
  • The video of the building: i link it...
Read more »

Adobe Portable Document Format - 82.65 kB - 07/07/2020 at 00:34


Standard Tesselated Geometry - 316.59 kB - 07/04/2020 at 16:22


Standard Tesselated Geometry - 316.59 kB - 07/04/2020 at 16:22


Standard Tesselated Geometry - 273.52 kB - 07/04/2020 at 16:22


Standard Tesselated Geometry - 273.52 kB - 07/04/2020 at 16:22


View all 24 files

  • 12 × Servo DS3218 PRO version. 20 kg/cm torque and 0.1 s/60º.
  • 1 × MPU6050 IMU. accelerometer + gyrocope.
  • 1 × Arduino Mega.
  • 1 × Raspberry Pi 4. 1Gb RAM.
  • 1 × Remote Controller In my case original ps3 controller DualSock 3.

View all 8 components

  • Quadruped robot meets my cat.

    Miguel Ayuso Parrilla07/07/2020 at 18:29 0 comments

    As a quick update of the V2 robot performing i have introduced it to my cat.

    My cat is very introverted and usually doesn't like new things, in this case isn't different but it seems to cause she some curiosity.

    The robot performs well, as it uses the last version of the code, the extra weigth of the batteries and raspberry pi is not a problem as the new design is much more lighter and the servos are now powered at 6V in stead of 5V as in the first version.

    On the other hand, i have notice the model randomly gives bad solutions running on the raspberry pi, thats why sometimes you see the leg make a strange movement. I haven't identify the problem yet, maybe is my software problem or bufer overflow.

    There is no aim to hurt the animal, is my cat omg.

  • Real robot vs PyBullet simulation.

    Miguel Ayuso Parrilla06/26/2020 at 14:45 0 comments

    In this video i compare the real robot model with the simulation model:

    I'm using PyBullet physics engine, it is simple to use and seems to have a good performance as well as very precise results. In the video you can see that the simulation is a bit slow, this is becouse the simulation (at the time of the video) was not working at real time but computing the simulation every 20 ms.

  • Raspberry Pi communication interfaces.

    Miguel Ayuso Parrilla06/21/2020 at 21:41 0 comments

    This log is going to be about the python communication files, explaining the interfaces used in order to communicate both with the ps3 controller and with the arduino.

    Serial Bidirectional Communication on python.

    This is written in the file and the code goes as follow:

    • First thing is to define the serial port and its baudrate.
    import serial
    class ArduinoSerial: 
        def __init__(self , port):
            #ls -l /dev | grep ACM to identify serial port of the arduino
            self.arduino = serial.Serial(port, 500000, timeout = 1)
            self.arduino.setDTR(False) #force an arduino reset
    • Then the communication is done with the next two fuctions. This fuctions are very general and can be used without big chnges.

      This program will stop the main loop until the next data arrives, this way the arudino memory is not overloaded with the pulse commands arriving.

    def serialSend(self, pulse):  
            comando = "<{0}#{1}#{2}#{3}#{4}#{5}#{6}#{7}#{8}#{9}#{10}#{11}>" #Input
            command=comando.format(int(pulse[0]), int(pulse[1]), int(pulse[2]), 
                                       int(pulse[3]), int(pulse[4]), int(pulse[5]), 
                                       int(pulse[6]), int(pulse[7]), int(pulse[8]), 
                                       int(pulse[9]), int(pulse[10]), int(pulse[11]))
            self.arduino.write(bytes(command , encoding='utf8'))
        def serialRecive(self):
                startMarker = 60
                endMarker = 62
                getSerialValue = bytes()
                x = "z" # any value that is not an end- or startMarker
                byteCount = -1 # to allow for the fact that the last increment will be one too many
                # wait for the start character
                while  ord(x) != startMarker: 
                    x =
                    # save data until the end marker is found
                while ord(x) != endMarker:
                    if ord(x) != startMarker:
                        getSerialValue = getSerialValue + x 
                        byteCount += 1
                    x =
                loopTime , Xacc , Yacc , roll , pitch  = numpy.fromstring(getSerialValue.decode('ascii', errors='replace'), sep = '#' )  

    Connecting PS3 controller to the Raspberry Pi and reading its events.

    • Then events are read on the file, using evdev python library. In this set up, the events are read every time the read() function is called, ignoring the others intermediate events. Also there isn't any queue method.
    from evdev import InputDevice, categorize, ecodes
    from select import select
    import numpy as np
    class Joystick:
        def __init__(self , event):
            #python3 /usr/local/lib/python3.8/dist-packages/evdev/ for identify event
            self.gamepad = InputDevice(event)
        def read(self):
            r,w,x = select([self.gamepad.fd], [], [], 0.)
            if r:
                for event in
                    if event.type == ecodes.EV_KEY:
                        if event.value == 1:
                            if event.code == 544:#up arrow
                                self.T += 0.05
                            if event.code == 545:#down arrow
                                self.T -= 0.05
                            if event.code == 308:#square
                                if self.compliantMode == True:
                                    self.compliantMode = False
                                elif self.compliantMode == False:
                                    self.compliantMode = True    
                            print("boton soltado")
                    elif event.type == ecodes.EV_ABS:
                        absevent = categorize(event)
                        if ecodes.bytype[absevent.event.type][absevent.event.code] == "ABS_X":  
                        elif ecodes.bytype[absevent.event.type][absevent.event.code] == "ABS_Y":
                        elif ecodes.bytype[absevent.event.type][absevent.event.code] == "ABS_RX":
                        elif ecodes.bytype[absevent.event.type][absevent.event.code] == "ABS_RY":

  • A simple walking method.

    Miguel Ayuso Parrilla06/15/2020 at 00:39 0 comments

    This experimet was the first one done on the robot, it consist on a very simple arduino sketch, implementing the IK equations and a simple creep gait loop with 4 points bezier curves.

    This only walks forward to the infinite, but is a useful example of the IK equations written on arduino language, here is the Arduino-quadruped-robot-loop repositorie from my github.

  • Role of Arduino and Serial Communication.

    Miguel Ayuso Parrilla06/12/2020 at 21:34 0 comments

    Working frequencies.

    Arduino is used as a pwm signal generator for the servos, so the main loop must run at the duty frequency of the servos (in my case 50Hz, 20ms loop). Of course, arduino is more powerful than that, so after sending a first pulse and before the next pulse is sent, arduino will read the different sensors, send their data and recive the next pulse command from the raspberry pi (via bidirectional serial commands).

    As the arduino loop is limited by the frequency of the servos, the main python code will also work at that frequency. As far as i know, this is because if the model gives a solution every 5ms and the actuators can only read a solution every 20ms, there will be 'useless' solutions given, resulting with the system not behaving as desired.

    Arduino sketch.

    The arduino code is very simple, but a bit long. Basically, it is composed by two files, main program: arduino_com.ino and the IMU functions: gy_521_send_serial.ino (Code by "Krodal"), this includes a low pass filter for the orientation. It works very well, without any fiffo problems but there is lot of drift on the yaw angle.

    About the main code:

    void loop() {
      unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= interval) {
          previousMillis = currentMillis;
          newData = false;
          moveServos(pulse0, pulse1, pulse2, pulse3, pulse4, pulse5, pulse6, pulse7, pulse8, pulse9, pulse10, pulse11);

     Is basically what i exaplined, it only works when 20ms has passed and then it reads the angles from IMU, read the incoming pulses via serial command, switch newData flag off and write the new pulses command.

    The pulses are given on microseconds, the translation of angles to microseconds is done in the python code.


    How commands are read and then converted to an integer is made with this function, which is from: Serial Input Basics - updated.

    Here there is the example i used:

    // Example 3 - Receive with start- and end-markers
    const byte numChars = 32;
    char receivedChars[numChars];
    boolean newData = false;
    void setup() {
        Serial.println("<Arduino is ready>");
    void loop() {
    void recvWithStartEndMarkers() {
        static boolean recvInProgress = false;
        static byte ndx = 0;
        char startMarker = '<';
        char endMarker = '>';
        char rc;
        while (Serial.available() > 0 && newData == false) {
            rc =;
            if (recvInProgress == true) {
                if (rc != endMarker) {
                    receivedChars[ndx] = rc;
                    if (ndx >= numChars) {
                        ndx = numChars - 1;
                else {
                    receivedChars[ndx] = '\0'; // terminate the string
                    recvInProgress = false;
                    ndx = 0;
                    newData = true;
            else if (rc == startMarker) {
                recvInProgress = true;

     What i have done is to add an spacer ('#') to differentiate each pulse and a counter, that is in charge of saving the numeric string to its correspoding integer pulse.

  • Hitting the robot.

    Miguel Ayuso Parrilla06/12/2020 at 11:30 0 comments

    I manage to make the robot a bit compliant by reading acceleration meassurements on the IMU, when a big acceleration is showed, a velocity command (in direction of the perturbance) is hold in order to soften that disturbance.

    In the video the model is reading raw acceleration data, thats why sometimes its has random movements.

  • Step Trajectory and Gait Planner (from MIT cheetah)

    Miguel Ayuso Parrilla05/31/2020 at 13:17 0 comments

    As in the you can change the foot position, you can make a time varying system by changing the feet position describing a bezier curve.

    So building a parametric bezier curve (11 points for now) you can follow a closed step loop, i drew this curve on this bezier curve generator:

    This can by written by an equation dependant of the N point and a parameter going from 0 to 1 in order to describe the trajectory. In the the file is known as phi and the start-end point is [0,1). This parameter is important, because it tells you where the foot is located, these coordinates are defined in the foot frame.

    The equations are based on the paper Leg Trajectory Planning for Quadruped Robots with High-Speed Trot Gait from the MIT cheetah robot (equations 11-23-24-TABLE II).

    But in my case, i chose similar points but with 10 points (removing P6 and P4) and i'm just multiplying all points by a velocity command in order to make the trajectory wider.

                                                                      Trajectory of step at different speeds

    Also for every loop, the swing and stance loops are running, each from 0 to 1, first stance phase then swing, with an offset between them which, if it is set at 0.5, both phases last the same. I another case, for creep gait, this offset must be set at 0.75, meaning that stance phase will last 3/4 of the step.

    Then making 4 loops going from 0 to 1, for every leg and define an offset for every foot you can do different gaits as shown in the video.

    In the video i explain how you can generate different gaits just by changing the offset between the feet loop:

    You can play with the simulation at the file just python3 with pybullet and numpy needed to run the simulation.

  • Lets talk about the kinematic model.

    Miguel Ayuso Parrilla05/14/2020 at 12:10 0 comments

    In this first log i'm going to explain how the kinematic model works.

    First thing to take into account is the robot geometry and its DOFs, to ilustrate this, in the next image you see where are they and how they transform. This model is very looking forward, in real robotics first is to make a robust state stimator so you can have smooth meassurements of robots states.

    NOTE: All vector are defined inside the robot frame, no world frame is used for now.

    So, we have 4 frames on each leg and one which is commun for all, which is the geometric center of the robot (very close to the CoM).

    For our setup, there are 2 important frames on the leg, which are the frame0 (coxa frame or first frame on the leg) and frame4 (foot frame or last frame on the leg).

    So now, we are going to calculate Inverse Kinematics between those frames. If you want more information on how to calculate IK you can read this article:

    As u can see the setup is a bit diferent, but it only change the simetry of the legs, so the analytic function is the same.

    Inverse Kinematics are solved on the file, which is basically two functions, one for right legs and the other for the left legs. These functions works as shown:

    Now, we can locate foot in the 3D space, inside the frame0.

    Next step is to move the body frame in relation with the feet. Which is essentialy the kinematic model i built, file in the code.

    For this, we need to define 3 vectors, the first is a 'constant' vector, which is the vector from the center to the frame0 or coxa frame, this vector is going to be rotated and translated with the desired body position.

    The next is the vector from body frame to frame4 or foot frame, this vector is where we want the foot to stay.

    With this two vector we can calculate the IK vector needed for the inverse kinematics just by subtracting body to frame4 and body to frame0.

    Now, we want the body to rotate on its 3 dofs and its 3 logitudinal movements, for this, we just multiply the body to frame0 vector by the rototranslation matrix.

    You can see how this woks on the file, where the fuctions for the rototranslations are defined. Here there is a figure to ilustrate the rotation of the body with respect to the feet in the pitch rotation:

    As the the principal frame is transformed, all other child frames are also transformed,  so in order to keep feet still, we need to undo the fransformation for the frame0 to frame4 vector (IK vector) before IK are solved.

    Here there is a video showing the model in action:

    As you see in the video, you can define a initial position for the feet and vary the 6 dof on the body frame, that it may be, for example, the states of a control model.

View all 8 project logs

  • 1
    Building premises.

    I'm going to enumerate some important concepts i have taken into account for the robot design.

    • This robots depends hardly on its mass distribution and dynamics of the moving parts (legs). Thats why i decided to go for this servo configuration, having the coxa servo on the body, the femur servo on the coxa and tibia servo on the the femur, so there is only 2 servos moving with the legs.
    • This way, the less leg weight the less unexpected inertia, causing a better dynamic behavior.
    • Also the robot weight should be as less as posible becouse hobby servos can be overcharged easily.
    • About the mass distribution, this would define the Center of Mass which should be the closest to the Geometric Center, for this the building must be as simetric as posible, this way CoM is easier to locate and the control would be more predictable.
    • The lenght of the leg is defined at 100 mm for both tibia a femur, this way, a motor with 20 Kg/cm will hold 2 kg at a 10 cm arm. So the longer the arm, the less force the motor can support.
    • Avoid plastic vs plastic joints, this would involve unnecessary friction forces.

    Printing premises.

    • This is simple but is important to take this into account, at the time of printing, these parts are not supporting much mechanical forces, for this and taking into account building premises, the 3D printed parts should be printed with ~10-20% infill , 1-2 outer perimeters and 2-3 solid layers.
  • 2
    Building and printing the robot.

    For building this i have made this tutorial, as there are some tricky parts.

    In the file section, each STL is named with the quantity of parts you need to print, if none just one needs to be printed.

    Also you can download them all at once at my git repo:

    Bolt list:

    • M3 x45 mm: quantity 12
    • M3 x30 mm: quantity 26
    • M3 x25 mm: quantity 16
    • M3 x20 mm: quantity 8
    • M3 x15 mm: quantity 16
    • M3 x7 mm: quantity 4
    • M3 threaded rod x 42 mm: quantity 4
    • M3 threaded rod x 74 mm: quantity 8

    Plus its respectives nuts and washers where is needed.

  • 3

    Here is the electronics setup i have:

    You can download the full size PDF file of the scheme at the file section.

    As you can see, appart from the 4 power lines in order to power the servomotors, there is also a voltage divider in order to read the batterie voltage in the arduino from an analog pin and then 5 LEDs will indicate the batterie status. Finally, IMU is connected via I2C interface. Raspberry pi is powered via another bulk converter at 5V 3A, that i miss (i will correct this in the next updates) and arduino communicates via USB cable (which also power it) to raspberry pi.

    I made two modular small boards in order to easily connect and disconnect servos, these boards are conected to the big one, which will supply all the pins to the arduino, being the 12 pwm signals with its commun ground and the I2C interface for the IMU. Also here, i can add sensors (FRS) the same way for the future.

View all 3 instructions

Enjoy this project?



Caleb wrote 2 days ago point

Do you cut the threaded rod to length (42 mm, 74 mm), or are you purchasing them in those lengths?

What washers are you using (as shown in the build video), what are the specifications?

  Are you sure? yes | no

Caleb wrote 2 days ago point

Sorry, not washers, bearings -- ball/flange bearings?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote a day ago point

I cut them, as i have the tools needed at home. About the bearings, as components sugest, they are the typical ball bearing with 3mm inner x 8mm outer x 4mm width.

Anyway Caleb, at this repo there is the STEP model, if you want to check bolt dimentions or what needed (this repo is from the awesome spot micro community, there is lot of research there):

  Are you sure? yes | no

Caleb wrote 07/07/2020 at 04:02 point

Where are the batteries in the V2 design -- is that the red underbelly area?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 07/07/2020 at 15:20 point

Just under the body, you can check how it goes at the building video

  Are you sure? yes | no

Nicola Russo wrote 07/05/2020 at 14:10 point

Hello! I just want to let you know that your project largely inspired the kinematics model for my experiment ( Of course I've put your name and the link to this project in the credits section. Hopefully I can inspire you as well! :)

Well done!!

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 07/06/2020 at 12:39 point

Hi Nicola. This is amazing!! Your project is also very well documented, i will take a look at it! I'm happy to know it has been useful for you and thanks for spending your time reading my project. Together we are building something very big!


  Are you sure? yes | no

dev1122 wrote 07/02/2020 at 16:12 point

what is the use of file, please help regarding that.

  Are you sure? yes | no

Chamika Ekanayaka wrote 06/29/2020 at 21:35 point

Hey there! Good job on the project, I was wondering if I could replicate this whole system, but I couldn't find any files for the 3D parts or any schematics to follow up, would these ever be available and how long would it take?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 07/02/2020 at 15:47 point

I'm just working on it! i promise you to release all the 3d model files in 2 weeks max, i have just finished printing the final version and i'm starting to documentate all the building process, stay tuned man!

  Are you sure? yes | no

Alan Churichi wrote 06/20/2020 at 18:04 point

Hi! Really nice work!

Do you have schematics files for the connections?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 06/21/2020 at 21:01 point

Thanks Alan! I'm working on it, as soon as i solder the new electronics i will post the schematics.

  Are you sure? yes | no

albertson.chris wrote 05/15/2020 at 00:40 point

Will you post th CAD files?   Already I'd like to try building just one leg for testing and I can think of a few changes.

One other question:  It looks like the prototype in the video was missing the Pi and batteries.  How much weight could be added?   Certainly the Pi4, batteries and see DC/DC regulator will need to be addd but also some sensors.

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 05/15/2020 at 10:07 point

Yes! i'm finishing them, i think in the next 3 month i will print all the parts left, correct them if there are mistakes and then share them.

Yes, batteries, raspi and its cables are taken into account in the design, they add about 500-700 g, but also i'm removing weight in the design. Another diference between prototype and wireless version is that cable is going at 5V and batteries at 7.4V.

So i think, there will be no problem with this extra weight

  Are you sure? yes | no

Mustafa wrote 05/14/2020 at 18:11 point

If you prepare a basic udemy course we can buy it

  Are you sure? yes | no

Mustafa wrote 05/14/2020 at 16:50 point

Miguel I am following your project, thanks for those precious informations.. Please continue..

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 05/15/2020 at 10:08 point

Thanks a lot man! Of course i'll be documenting all the project.

  Are you sure? yes | no

Comedicles wrote 05/14/2020 at 06:17 point

Does it have accelerometers and inertial orientation? Put the poor thing out of its misery and place it on a  rubber surface so that leg motion can correspond to movement through space. I can tell it is miserable!

  Are you sure? yes | no

Steve wrote 05/13/2020 at 17:23 point

I loaded the STLs into Ideamaker(3D-printer slicer) and it shows up super-tiny, like it's in inches not millimeters. What are the dimensions supposed to be  if we wanted to print this out ?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 05/13/2020 at 22:40 point

Those files are not printable, are only for show them on the simulation, thats why u see them very small as they are meassured on meters. If you look closer to them, there is no way to build or mount them with the hardware

  Are you sure? yes | no

Steve wrote 05/14/2020 at 00:10 point

Is there a way to print it out if we wanted to work on one ourselves or is that not ready yet ?

  Are you sure? yes | no

Steve wrote 05/14/2020 at 00:14 point

Anyway, this is still very cool and I'm looking forward to reading about it more as it progresses along.

  Are you sure? yes | no

Alior101 wrote 05/13/2020 at 16:34 point

Cool! Is this the 180 or 270 pro version of  DS3218?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 05/13/2020 at 17:17 point

180 PRO version, as for example, the tibia movement is limited to 110 dregrees.

  Are you sure? yes | no

Alex Tacescu wrote 05/13/2020 at 15:58 point

Super cool project! Are you calculating forward/inverse kinematics on the Arduino? Or is everything done in the physics engine?

  Are you sure? yes | no

Miguel Ayuso Parrilla wrote 05/13/2020 at 17:21 point

I'm calculating them on the python sketch in the computer/raspberry. For now i'm not using data from the simulation, only i sent to the simulation the angles for every joint, the same as in the real robot.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates