Machine mechanics

Lesson 15

This week's assignment is design or modify a machine, making as many of the components as possible. Document the group project and your individual contribution and make the passive parts and operate it manually. Secondly, automate the machine, document the group project and your individual contribution.

For this group assignment, we would like to make a pen plotter. Please have a look at this site too for information on this project.

We divided the work as follows: Mio would make the controlling PCB board, Maurice would make the Motor Boards and ready them for communication with the controlling PCB, Rick and Rein would make the mechanics of the machine and Michael would look at the mathematics of the polar coordinates system. Below, we you can see our first outline of the pen plotter. A board with an opening for two motors on the bottom(left and right) and on the top two pulleys which were connected by a string to the two motors.

On the left, you can see the eagle board layout of the motor board, which i designed to be able to communicate with the masterboard. On the right the two boards milled out on the modela and with the components soldered on top.

On the video below, you can see our second try to get the mechanics working. The mechanics of the pulleys and the wire connections with the motors are made by Rick and Rein.

After making the machine board, my first task was to get the a communication board to communicate with one motor board via the serial port and leave the second motor out of the picture for the moment.

After succesfully talking to one single motor board via the serial port, i added the second motor to the bus and tried to talk to the motor individually via the serial port. In this case, i talked to the motors by sending manually control signals via the serial port. Next step is to automate this process.

I programmed a sequence of commands in the program and let it execute automatically. On the video below, you can see the two motors automatically operated.

At this point, we can control the two motors automatically. Up to this point, we did not include Mio's masterboard or program his board to send the data in a correct polar format. Why polar format? If we have a dxf format drawing and we would send the cartesian data to the motors, we would not get the desired result. We need to calculate how much each motor has to pull or release simultanously to get a fluent movement from one point to another. As we have only one reference point for each motor, we need to use polar coordinate calculations to get the right pull and release calculations. By looking at several sites on polar coordinate systems, i found that we needed to use pythagoras theorem to calculate the distance of each rope. After some trial and error, i found a way to calculate the distance of each rope on each point of time going from one point to another. I programmed this code onto Mio's masterboard and added the dxf drawing to be drawn. This worked successfully. Next step was to get it to work. Rick, Rein and Michael soon found out that the motor, we have been using were not strong enough to pull the pen holder, so we needed to change our original idea and made the pen holder a lighter pointing device. The code works, but we have not been able to get the entire machine operational.

Below, you will find first the code of the masterboard with the polar coordinates calculation and after that the code for the motor board.

masterboard code

//
//
// hello.bus.45.c
//
// 9600 baud serial bus hello-world
//
// Neil Gershenfeld
// 11/24/10
// Maurice Op de Beek
// 01/07/13
// Polar Coordinate System
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

#include 
#include 
#include 
#include 
#include 
#include 
#include     
#define swap(a,b) t=a;a=b;b=t;

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 104 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define led_delay() _delay_ms(100) // LED flash delay

//#define led_port PORTB
//#define led_direction DDRB
//#define led_pin (1 << PB0)

#define serial_port PORTD
#define serial_direction DDRD
#define serial_pins PIND
#define serial_pin_in (1 << PD0) 
#define serial_pin_out (1 << PD1) 
//#define serial_pin_cts (1 << PD2) // CTS // GREEN PIN MIO

#define node_id '0'



void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
   //
   // read character into rxbyte on pins pin
   //    assumes line driver (inverts bits)
   //
   *rxbyte = 0;
   while (pin_test(*pins,pin))
      //
      // wait for start bit
      //
      ;
   //
   // delay to middle of first data bit
   //
   half_bit_delay();
   bit_delay();
   //
   // unrolled loop to read data bits
   //
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 0);
   else
      *rxbyte |= (0 << 0);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 1);
   else
      *rxbyte |= (0 << 1);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 2);
   else
      *rxbyte |= (0 << 2);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 3);
   else
      *rxbyte |= (0 << 3);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 4);
   else
      *rxbyte |= (0 << 4);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 5);
   else
      *rxbyte |= (0 << 5);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 6);
   else
      *rxbyte |= (0 << 6);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 7);
   else
      *rxbyte |= (0 << 7);
   //
   // wait for stop bit
   //
   bit_delay();
   half_bit_delay();
   }

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   // start bit
   //
   clear(*port,pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,1)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,2)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,3)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,4)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,5)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,6)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,7)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   //
   // stop bit
   //
   set(*port,pin);
   bit_delay();
   //
   // char delay
   //
   bit_delay();
   }

void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   static char chr;
   static int index;
   index = 0;
   do {
      chr = pgm_read_byte(&(str[index]));
      put_char(&serial_port, serial_pin_out, chr);
      ++index;
      } while (chr != 0);
   }

//void flash() {
   //
   // LED flash delay
   //
  // clear(led_port, led_pin);
  // led_delay();
  // set(led_port, led_pin);
 //  }
 
 void sendMotorInstruction(char chr){
         //output(serial_direction, serial_pin_out);
         //const static char message[] PROGMEM = "node ";
         //put_string(&serial_port, serial_pin_out, (PGM_P) message);
         
         put_char(&serial_port, serial_pin_out, chr);
         //while (!pin_test(PINB,serial_pin_cts));
         //put_char(&serial_port, serial_pin_out, 10); // new line
         // led_delay();
         //flash();
         //input(serial_direction, serial_pin_out);
} 

int main(void) {
   //
   // main
   //
   //static char chr;
   float arrx[3] = {1.0f,30.0f,15.0f};
   float arry[3] = {1.0f,30.0f,15.0f};
   double nail_dis = 30.00;
  // double t;
  //int r;
    int j; // cartesianstep loop
    double cartesianStep = 0.001; // step in the xy cartesian coordinates
    double machineStep=0.5; // length of minimum change in rope with one step of machine
    int i; // loop through array
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize output pins
   //
   set(serial_port, serial_pin_out);
   output(serial_direction, serial_pin_out);
   //set(led_port, led_pin);
  // output(led_direction, led_pin);
  //  input(serial_direction,serial_pin_cts);
   
   
   //
   // main loop
   //
   while (1) {
 //    get_char(&serial_pins, serial_pin_in, &chr); // input bel ringing
    //put_char(&serial_port, serial_pin_out, '9');  
      //code maurice
      
  for (i=0;i<2;i++){


  double x1 = arrx[i];
 // printf("x1 %0.2f \n",x1);
  double x2 = arrx[i+1];
 // printf("x2 %0.2f \n",x2);
  double y1 = arry[i];
//  printf("y1 %0.2f \n",y1);
  double y2 = arry[i+1];
  //printf("y2 %0.2f \n",y2);
  double oldleftwirelength = sqrt(x1*x1+y1*y1);
  double oldrightwirelength = sqrt((nail_dis-x1)*(nail_dis-x1)+y1*y1);


int totalCartesianSteps = fabs(x2-x1)/cartesianStep;
//printf("totalCartesianSteps: %d \n",totalCartesianSteps);

    for (j =0;j <=totalCartesianSteps;j++){
    
    double changeInx = x2 - x1; // change in x
    //  printf("changeXLeft: %0.2f\n", changeInx);
    double changeIny = y2 - y1; //change in y
    //printf("changeY: %0.2f\n", changeIny);
    //double changeInxRight = (nail_dis-x2) - (nail_dis-x1); // change in x
    // printf("changeXRight: %0.2f\n", changeInxRight);
    double relativeSpeed = fabs(changeInx)/fabs(changeIny);
    // move cartesian x and y with cartesianstep

                if (changeInx>0)  { x1 = x1 + cartesianStep;
                printf("x1-: ,%0.2f\n",x1);
          }
                else {x1 = x1 - cartesianStep;
                printf("x1+: ,%0.2f\n",x1);
            }
                // if cartesian x is negative then negative step else positive step
                // move y in ratio to x
                // if cartesian y is negative then negative steo else positive step
                if (changeIny>0)  {y1 = y1 + (cartesianStep/relativeSpeed);
                printf("y1-: ,%0.2f\n",y1);
        }
                else {y1 = y1 - (cartesianStep/relativeSpeed);
                 printf("y1+: ,%0.2f\n",y1);
         }


        double newleftwirelength = sqrt(x1*x1+y1*y1);
        double newrightwirelength = sqrt((nail_dis-x1)*(nail_dis-x1)+y1*y1);

        if(newleftwirelength>oldleftwirelength){
        if(fabs(newleftwirelength-oldleftwirelength) > machineStep){
           
            
             put_char(&serial_port, serial_pin_out, '7');
            // _delay_ms(100);
            //printf("ReleaseLeft\n");
            oldleftwirelength = newleftwirelength;
        }
        }


        if(newleftwirelength machineStep){
            
            put_char(&serial_port, serial_pin_out, '5');
           //_delay_ms(100);
            //printf("PullLeft\n");
            oldleftwirelength = newleftwirelength;
        }
        }

        if(newrightwirelength>oldrightwirelength){
        if(fabs(newrightwirelength-oldrightwirelength) > machineStep){
           
            put_char(&serial_port, serial_pin_out, '1');
            //_delay_ms(100);
            //printf("ReleaseRight\n");
            oldrightwirelength = newrightwirelength;
        }
        }


        if(newrightwirelength machineStep){
            
             put_char(&serial_port, serial_pin_out, '3');
             //_delay_ms(100);
            //printf("PullRight\n");
            oldrightwirelength = newrightwirelength;
        }
        }



  }
  }

      }  // end of while loop
   } // end of main

motor code Number 1 (left) and 3(right) for motor 1. Number 5 (left) and 7 (right) for motor 2.


//
//
// hello.stepper.44.half.c
//
// half stepping hello-world
//
// Neil Gershenfeld
// 11/14/10
//
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

#include 
#include 

// extra from bus
#include 
#include 

//atoi
#include      /* atoi */

// MOTOR DEFINE
#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set

#define MOSFET_port PORTA // MOSFET port
#define MOSFET_direction DDRA // MOSFET direction
#define brown (1 << PA0) // MOSFET output pins
#define black (1 << PA1) // "
#define yellow (1 << PA2) // "
#define orange (1 << PA3) // "
#define on_delay() _delay_us(50) // PWM on time
#define off_delay() _delay_us(10) // PWM off time
#define PWM_count 100 // number of PWM cycles
// END OF MOTOR DEFINE

//BUS DEFINE
//#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
//#define set(port,pin) (port |= pin) // set port pin
//#define clear(port,pin) (port &= (~pin)) // clear port pin
//#define pin_test(pins,pin) (pins & pin) // test for port pin
///#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set

#define bit_delay_time 100 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
//#define led_delay() _delay_ms(100) // LED flash delay

//#define led_port PORTB
//#define led_direction DDRB
//#define led_pin (1 << PB0)
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pins PINB
#define serial_pin_out (1 << PB0) //RX  // GREY
#define serial_pin_in (1 << PB1) //TX // PURPLE
#define serial_pin_cts (1 << PB2) // CTS // GREEN 





// DEFINING OF MOTOR
#define node_id '1'
// END OF BUS DEFINE

// MOTOR VARIABLE
static uint8_t count;
const static char message[] PROGMEM = "motor ";




//MOTOR FUNCTIONS
//
// yellow PWM pulse
//
void pulse_yellow() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, yellow);
      on_delay();
      clear(MOSFET_port, yellow);
      off_delay();
      }
   }
//
// black PWM pulse
//
void pulse_black() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, black);
      on_delay();
      clear(MOSFET_port, black);
      off_delay();
      }
   }
//
// orange PWM pulse
//
void pulse_orange() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, orange);
      on_delay();
      clear(MOSFET_port, orange);
      off_delay();
      }
   }

//
// brown PWM pulse
//
void pulse_brown() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, brown);
      on_delay();
      clear(MOSFET_port, brown);
      off_delay();
      }
   }
//
// yellow, brown PWM pulse
//
void pulse_yellow_brown() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, yellow);
      set(MOSFET_port, brown);
      on_delay();
      clear(MOSFET_port, yellow);
      clear(MOSFET_port, brown);
      off_delay();
      }
   }
//
// yellow, black PWM pulse
//
void pulse_yellow_black() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, yellow);
      set(MOSFET_port, black);
      on_delay();
      clear(MOSFET_port, yellow);
      clear(MOSFET_port, black);
      off_delay();
      }
   }
//
// orange, brown PWM pulse
//
void pulse_orange_brown() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, orange);
      set(MOSFET_port, brown);
      on_delay();
      clear(MOSFET_port, orange);
      clear(MOSFET_port, brown);
      off_delay();
      }
   }
//
// orange, black PWM pulse
//
void pulse_orange_black() {
   for (count = 0; count < PWM_count; ++count) {
      set(MOSFET_port, orange);
      set(MOSFET_port, black);
      on_delay();
      clear(MOSFET_port, orange);
      clear(MOSFET_port, black);
      off_delay();
      }
   }
//
// clockwise step
//
void step_cw() {
   pulse_yellow_brown();
   pulse_yellow();
   pulse_yellow_black();
   pulse_black();
   pulse_orange_black();
   pulse_orange();
   pulse_orange_brown();
   pulse_brown();
   }
//
// counter-clockwise step
//
void step_ccw() {
   pulse_brown();
   pulse_orange_brown();
   pulse_orange();
   pulse_orange_black();
   pulse_black();
   pulse_yellow_black();
   pulse_yellow();
   pulse_yellow_brown();
   }
   
// END OF MOTOR FUNCTIONS


// BUS FUNCTIONS
void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
   //
   // read character into rxbyte on pins pin
   //    assumes line driver (inverts bits)
   //
   *rxbyte = 0;
   while (pin_test(*pins,pin))
      //
      // wait for start bit
      //
      ;
   //
   // delay to middle of first data bit
   //
   half_bit_delay();
   bit_delay();
   //
   // unrolled loop to read data bits
   //
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 0);
   else
      *rxbyte |= (0 << 0);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 1);
   else
      *rxbyte |= (0 << 1);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 2);
   else
      *rxbyte |= (0 << 2);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 3);
   else
      *rxbyte |= (0 << 3);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 4);
   else
      *rxbyte |= (0 << 4);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 5);
   else
      *rxbyte |= (0 << 5);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 6);
   else
      *rxbyte |= (0 << 6);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 7);
   else
      *rxbyte |= (0 << 7);
   //
   // wait for stop bit
   //
   bit_delay();
   half_bit_delay();
   }

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   // start bit
   //
   clear(*port,pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,1)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,2)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,3)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,4)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,5)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,6)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,7)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   //
   // stop bit
   //
   set(*port,pin);
   bit_delay();
   //
   // char delay
   //
   bit_delay();
   }

void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   static char chr;
   static int index;
   index = 0;
   do {
      chr = pgm_read_byte(&(str[index]));
      put_char(&serial_port, serial_pin_out, chr);
      ++index;
      } while (chr != 0);
   }

//void flash() {
   //
   // LED flash delay
   //
 //  clear(led_port, led_pin);
 //  led_delay();
 //  set(led_port, led_pin);
 //  }

// END OF BUS FUNCTIONS

int digit_to_int(char d)
{
 char str[2];

 str[0] = d;
 str[1] = '\0';
 return (int) strtol(str, NULL, 10);
}

int main(void) {
   //
   // main
   // BUS VARIABLES
   static char chr;
  
 
   // MOTOR VARIABLES
   //static uint8_t i; //,j;
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   
   // clock divider is same for BUS AND MOTOR
   // CLKPR = (1 << CLKPCE);
   // CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   
      
   
   
   // motor initialize MOSFET pins
   //
   clear(MOSFET_port, brown);
   output(MOSFET_direction, brown);
   clear(MOSFET_port, black);
   output(MOSFET_direction, black);
   clear(MOSFET_port, yellow);
   output(MOSFET_direction, yellow);
   clear(MOSFET_port, orange);
   output(MOSFET_direction, orange);
   
   
   //
   // bus initialize output pins
   //
   set(serial_port, serial_pin_out);
   input(serial_direction, serial_pin_out);
   output(serial_direction,serial_pin_cts);
  // set(led_port, led_pin);
  // output(led_direction, led_pin);
   //
   // main loop
   //
   while (1) {
      get_char(&serial_pins, serial_pin_in, &chr);
     // flash();
    //  char a = chr;
    //  PORTB |= (1 << serial_pin_cts); //off

      
      
      if (chr =='1') { // change 1 to 5 for motor 2
      
       step_ccw();
     // output(serial_direction, serial_pin_out);
     // put_string(&serial_port, serial_pin_out, (PGM_P) message);
     // put_char(&serial_port, serial_pin_out, chr);
     // put_char(&serial_port, serial_pin_out, 10);
    //  input(serial_direction, serial_pin_out); 
            
      
      
      }
      
      if (chr == '3') { // change 3 to 7 for motor 2
      step_cw();
     // output(serial_direction, serial_pin_out);
     // put_string(&serial_port, serial_pin_out, (PGM_P) message);
     // put_char(&serial_port, serial_pin_out, chr);
      //put_char(&serial_port, serial_pin_out, 10);
      //input(serial_direction, serial_pin_out);  
      

      }
//      PORTB &= ~(1 << serial_pin_cts); // on 
      }
      
      }