diff --git a/src/mtn_downloader/CMakeLists.txt b/src/mtn_downloader/CMakeLists.txt
new file mode 100755
index 0000000000000000000000000000000000000000..0fcb718b0fc6d3253c066f0773257632b6fd533c
--- /dev/null
+++ b/src/mtn_downloader/CMakeLists.txt
@@ -0,0 +1,35 @@
+# locate the necessary dependencies
+FIND_PACKAGE(iriutils REQUIRED)
+FIND_PACKAGE(comm REQUIRED)
+FIND_PACKAGE(robotis_bin_parser REQUIRED)
+FIND_PACKAGE(robotis_mtn REQUIRED)
+FIND_PACKAGE(robotis_mtn_parser REQUIRED)
+
+# add the necessary include directories
+INCLUDE_DIRECTORIES(.)
+INCLUDE_DIRECTORIES(${iriutils_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${comm_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${robotis_bin_parser_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${robotis_mtn_parser_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${robotis_mtn_INCLUDE_DIR})
+
+# application source files
+SET(sources mtn_downloader.cpp)
+# application header files
+SET(headers mtn_downloader.h)
+
+# create the executable file
+ADD_EXECUTABLE(mtn_downloader ${sources})
+
+# link necessary libraries
+TARGET_LINK_LIBRARIES(mtn_downloader ${iriutils_LIBRARY})
+TARGET_LINK_LIBRARIES(mtn_downloader ${comm_LIBRARY})
+TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_bin_parser_LIBRARY})
+TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_mtn_parser_LIBRARY})
+TARGET_LINK_LIBRARIES(mtn_downloader ${robotis_mtn_LIBRARY})
+
+INSTALL(TARGETS mtn_downloader
+        RUNTIME DESTINATION bin
+        LIBRARY DESTINATION lib/iridrivers
+        ARCHIVE DESTINATION lib/iridrivers)
+
diff --git a/src/mtn_downloader/mtn_downloader.cpp b/src/mtn_downloader/mtn_downloader.cpp
new file mode 100755
index 0000000000000000000000000000000000000000..5ec37cc469377d13665c692ea8d8d2e889835c55
--- /dev/null
+++ b/src/mtn_downloader/mtn_downloader.cpp
@@ -0,0 +1,282 @@
+#include "eventexceptions.h"
+#include "eventserver.h"
+#include "exceptions.h"
+#include "rs232.h"
+#include "mtn_file_parser.hpp"
+#include "robotis_bin_parser.h"
+#include "mtn_exceptions.h"
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdio.h>
+#include <iostream>
+#include <sys/stat.h>
+
+const unsigned char bootloader_ping='#';
+const unsigned char bootloader_ack='\n';
+const unsigned char bootloader_load[]="l 0x0001E000\0";
+const unsigned char bootloader_go='g';
+
+#define MTN_FILE_SIZE (128*1024)
+
+void show_help(char *name) 
+{
+  std::cout << "Usage: " << name << "-d <serial device> -f <firmware file> -p <protocol> [-h]" << std::endl;
+  std::cout << "       -d serial_device  Linux serial device used to communicate" << std::endl;
+  std::cout << "       -m motion_file    desired motion file in either .mtn or .bin format" << std::endl;
+  std::cout << "       -h                shows this help" << std::endl;
+}
+
+int main(int argc,char *argv[])
+{
+  // serial port objects
+  CEventServer *event_server=CEventServer::instance();
+  CRS232 serial_port("mtn_serial_dev");
+  std::list<std::string> events;
+  TRS232_config serial_config;
+  long int num_data=0,i=0;
+  bool end=false;
+  int option;
+  std::string opt_device,opt_mtn_file,mtn_ext;
+  // binary file variables
+  int bin_file_fd;
+  struct stat st;
+  unsigned char binary_file[MTN_FILE_SIZE];
+  long int downloaded_size=0;
+  long int start_address=0;
+  long int binary_size=0;
+  int block_size=0,count=0;
+  // bootloader variables
+  unsigned char bootloader_data[MTN_FILE_SIZE];
+  bool bootloader_connected=false;
+  unsigned char checksum=0x00;
+  // mtn file parser
+  MTN::CMtnFileParser mtn_parser;
+  CRobotisMtn motions;
+  CBinFileParser bin_parser;
+  std::string bin_filename;
+  std::string servo_type("AX-12A");
+
+  // configuration information for the serial device
+  serial_config.baud=57600;
+  serial_config.num_bits=8;
+  serial_config.parity=none;
+  serial_config.stop_bits=1;
+
+  memset(binary_file,0xFF,MTN_FILE_SIZE);
+
+  // parse the input arguments
+  while((option = getopt(argc, argv, "hd:m:")) != -1) 
+  {
+    switch(option) 
+    {
+      case 'h':// show help message
+        show_help(argv[0]);
+        break;
+      case 'd':// select serial device
+        std::cout << "Output device: " << optarg << std::endl;
+        opt_device=std::string(optarg);
+        break;
+      case 'm':// select motion file
+        std::cout << "Motion file: " << optarg << std::endl;
+        opt_mtn_file=std::string(optarg);
+        break;
+    }
+  }
+
+  // check that the two arguments have been entered
+  if(opt_device.size()!=0)
+  {
+    if(opt_mtn_file.size()==0)
+    {
+      std::cout << "No motion file has been specified" << std::endl;
+      show_help(argv[0]);
+      return 0;
+    }
+    else
+    {
+      try{
+        // open the serial port
+        serial_port.open((void *)&opt_device);
+        // configure the serial port
+        serial_port.config(&serial_config);
+        // get the recevice event
+        events.push_back(serial_port.get_rx_event_id());
+        // convert the hex file to a binary file
+        if(opt_mtn_file.size()!=0)
+        {
+          // check if the motion file is in .mtn format
+          if(opt_mtn_file.find(".mtn")!=std::string::npos)
+          {
+            std::cout << servo_type << std::endl;
+            try{
+              mtn_parser.parse(opt_mtn_file.c_str());
+              mtn_parser.get_motions(motions);
+              for(i=0;i<motions.get_num_servos();i++)
+                motions.set_motor_type(i,servo_type);
+              bin_parser.set_motions(motions);
+              bin_filename=opt_mtn_file;
+              bin_filename.replace(bin_filename.find(".mtn"),std::string(".mtn").length(),".bin");
+              bin_parser.serialize(bin_filename.c_str());
+            }catch(CMtnException &e){
+              std::cout << e.what() << std::endl;
+              return 0;
+            }
+            // open adn read the generated binary file
+            if((bin_file_fd=::open(bin_filename.c_str(),O_RDONLY))==-1)
+            {
+              std::cout << "Impossible to read the binary file" << std::endl;
+              return 0;
+            }
+          } 
+          else
+          {
+            if((bin_file_fd=::open(opt_mtn_file.c_str(),O_RDONLY))==-1)
+            {
+              std::cout << "Impossible to read the binary file" << std::endl;
+              return 0;
+            }
+          }
+          // check the binary file
+          stat(bin_filename.c_str(), &st);
+          if(st.st_size!=MTN_FILE_SIZE)
+          {
+            ::close(bin_file_fd);
+            std::cout << "Incorrect motion file size. It should be 128kB long" << std::endl;
+            return 0;
+          }
+          // read the file
+          if(::read(bin_file_fd,binary_file,MTN_FILE_SIZE)==-1)
+          {
+            ::close(bin_file_fd); 
+            std::cout << "Error while reading the motion file" << std::endl;
+            return 0;
+          }
+          // close the file
+          ::close(bin_file_fd); 
+          binary_size=MTN_FILE_SIZE;
+          start_address=0;
+        }
+        std::cout << "Switch off device power and turn it on" << std::endl;
+        // ping the device 
+        while(!bootloader_connected)
+        {
+          try{
+            event_server->wait_all(events,20);
+            num_data=serial_port.get_num_data();
+            serial_port.read((unsigned char *)bootloader_data,num_data);
+            bootloader_data[num_data]='\0';
+            printf("%s",bootloader_data);
+            fflush(stdout);
+            for(i=0;i<num_data;i++)
+            {
+              if(bootloader_data[i]=='#')
+              {
+                count++;
+                if(count==5)
+                  bootloader_connected=true;
+              }
+            }
+          }catch(CEventTimeoutException &e){
+            // do nothing and retry
+            serial_port.write((unsigned char *)&bootloader_ping, 1);
+          }
+        }
+        /* send acknowledgment to the device*/
+        serial_port.write((unsigned char *)&bootloader_ack, 1);
+        while(!end)
+        {
+          try{
+            event_server->wait_all(events,300);
+            num_data=serial_port.get_num_data();
+            serial_port.read(bootloader_data,num_data);
+            bootloader_data[num_data]='\0';
+            printf("%s",bootloader_data);
+            fflush(stdout);
+          }catch(CEventTimeoutException &e){
+            // the flash has been properly erased
+            end=true;
+          }
+        }
+        end=false;
+        // start the download
+        serial_port.write((unsigned char *)&bootloader_load,strlen((char *)bootloader_load));
+        serial_port.write((unsigned char *)&bootloader_ack,1);
+        while(!end)
+        {
+          try{
+            event_server->wait_all(events,300);
+            num_data=serial_port.get_num_data();
+            serial_port.read(bootloader_data,num_data);
+            bootloader_data[num_data]='\0';
+            printf("%s",bootloader_data);
+            fflush(stdout);
+          }catch(CEventTimeoutException &e){
+            // the flash has been properly erased
+            end=true;
+          }
+        }
+        // compute the binary file checksum
+        for(i=0;i<binary_size;i++)
+          checksum+=binary_file[start_address+i];
+        // send the binary file in 64 byte segments
+        while(downloaded_size < binary_size)
+        { 
+          usleep(1000);
+          block_size=binary_size-downloaded_size;
+          if(block_size>64)
+            block_size=64;
+          serial_port.write(&binary_file[start_address+downloaded_size],block_size);
+          downloaded_size+=block_size;
+          printf("\rDownloading Firmware (%ld/%ld byte)", downloaded_size, binary_size);
+          fflush(stdout);
+        }
+        // send the checksum
+        serial_port.write(&checksum,1);
+        std::cout << std::endl << "Download complete" << std::endl;
+        end=false;
+        while(!end)
+        {
+          try{
+            event_server->wait_all(events,300);
+            // there has been an error
+            num_data=serial_port.get_num_data();
+            serial_port.read(bootloader_data,num_data);
+            bootloader_data[num_data]='\0';
+            printf("%s",bootloader_data);
+          }catch(CEventTimeoutException &e){
+            // no error to report
+            end=true;
+          }
+        }
+        // start the loaded program
+        serial_port.write((unsigned char *)&bootloader_go,1);
+        serial_port.write((unsigned char *)&bootloader_ack,1);
+        end=false;
+        while(!end)
+        {
+          try{
+            event_server->wait_all(events,300);
+            // there has been an error
+            num_data=serial_port.get_num_data();
+            serial_port.read(bootloader_data,num_data);
+            bootloader_data[num_data]='\0';
+            printf("%s",bootloader_data);
+          }catch(CEventTimeoutException &e){
+            // no error to report
+            end=true;
+          }
+        }
+        serial_port.close();
+      }catch(CException &e){
+        /* handle exceptions */
+        std::cout << e.what() << std::endl;
+      }
+    }
+  }
+  else
+  {
+    std::cout << "No serial device specified" << std::endl;
+    show_help(argv[0]);
+  }
+}