Control Modeling

Control Modeling

Controlling a “printer head”

You are given a program modeling a printer head. The program executes sequentially like an infinite loop: It takes in 1 input, a number, and produces 1 output, another number, and then iterates. When the program terminates, it produces a result text file, containing all the data including the iteration number and the output from each iteration. The goal is to construct a program that implements a controller for the printer head. The purpose of the control program is to move the printer head to several locations in series and stabilize the output of the printer head at each location within a certain range for a certain number of iterations. It is supposed to mimic what happens in real time: The printer head must position itself “precisely” and then proceed with printing. This exercise is applicable to classical printers or, say, modern 3D printers.

Rules

Rule 1 There are only 3 input options for the printer head at each iteration. They are -1, 0 and 1. Anything else will result in an input of 0 to the printer head.
Rule 2 According to Rule1, you should keep the output of your controlling program to the printer head equal to -1, 0 or 1 as well.
Rule 3 Set the initial command to 0 when run the controller.
Rule 4 Do not change any of the \printer head code” unless specified otherwise.

Tasks

Task 1

Design a controller to make the output within the interval [9, 11] for 20 iterations.

Task 2

Once Task 1 is finished, move the printer head and make the output within the interval [4, 6] for 20 iterations.

Task 3

Once Task 2 is finished, move the printer head and make the output within the interval [-1, 1] for 20 iterations.

Task 4 Finish all the above tasks by 200 iterations.


Competition Finish all the above tasks with a final iteration number below the class average.

Figure 1: A figure showing a possible solution.

Procedures to Run
The procedures to follow in order for you to run the “printer head”.
1. Download all necessary files from the assignment page on T-square,and put them in a folder.
2. In the command line/terminal, change the directory to the folder containing all the files.
3. Compile the printer head program: gcc -o printerheadprinterhead.c
4. Modify the code in controller.c. These codes are the codes of yourcontroller.
5. Compile controller.c by typing in the command line: gcc -o controllercontroller.cOr use your favorite compile method.
6. Open another command line window, change the directory to the samefolder containing all the files, and run printerhead by typing: ./printerhead You will receive a port number, like “The server UDP portnumber is 59054″.
7. Go back to the first command line window, run the controller you compiled by typing: “./controller localhost 59054 0″.

Make surethe port number is correct and the last argument (the initialcommand) is 0.
8. After the controller program ends, go to the printerhead command line window and press “ctrl + c” to end the printerhead program.
9. Now, you have a \results.txt” file created in the same directory, withthe first column being the iteration number and the second columnbeing the output data..
10. (Optional) A “plot.py” file in python is provided that you can rundirectly and visualize the output vs. iteration number. Run the file bytyping: python plot.py

controller.c

#include <stdio.h>      /* standard C i/o facilities */

#include <stdlib.h>     /* needed for atoi() */

#include <unistd.h>     /* defines STDIN_FILENO, system calls,etc */

#include <sys/types.h>  /* system data type definitions */

#include <sys/socket.h> /* socket specific definitions */

#include <netinet/in.h> /* INET constants and stuff */

#include <arpa/inet.h>  /* IP address conversion stuff */

#include <netdb.h>      /* gethostbyname */

#include <string.h>

#define n_iterations 200

intsk; /* socket id */

intt_prev, i;

int goal;

structsockaddr_in server;

structhostent *hp;

float state[1001];

float command[1];

floatst, p_st;

typedefstruct {

int g;

floatcmd;

} out;

//Funtion for the command

outnew_command(float old_command, float current_state, float previous_state, float state[1001], int goal){

intidx = state[1000];

out output;

output.g = goal;

if(idx>= 20){

for(i=idx-20;i<idx;i++){

if(output.g == 1){

if(state[i]<9 || state[i]>11){

break;

}

if(i==idx-1){

output.g = 2; // 2nd Task

printf(“task 1 complete\n”);

}

}else if(output.g == 2){

if(state[i]<4 || state[i]>6){

break;

}

if(i==idx-1){

output.g = 3; // 3rd Task

printf(“task 2 complete\n”);

}

}else if(output.g == 3){

if(state[i]<-1 || state[i]>1){

break;

}

if(i==idx-1){

output.g = 4; // Task complete!

printf(“task 3 complete\n”);

printf(“Total iteration number: %f\n”, state[1000]);

}

}

}

}

// state[1000] is the iteration number

/*

*

*

* TYPE YOUR FUNCTION HERE TO COMPUTES THE NEW COMMAND

*

*

output.cmd = ???;

*/

return output;

}

int main( intargc, char **argv ) {

intj,n=0,len;

structsockaddr_in remote;

/* need to know how big address struct is, len must be set before the

call to recvfrom!!! */

len = sizeof(remote);

/* Make sure we have the right number of command line args */

if (argc!=4) {

printf(“Usage: %s <server name><port number><initial command value>\n”,argv[0]);

exit(0);

}

/* create socket

IP protocol family (PF_INET)

UDP (SOCK_DGRAM)

*/

if ((sk = socket( PF_INET, SOCK_DGRAM, 0 )) < 0)

{

printf(“Problem creating socket 1\n”);

exit(1);

}

server.sin_family = AF_INET;

if ((hp = gethostbyname(argv[1]))==0) {

printf(“Invalid or unknown host\n”);

exit(1);

}

/* copy the IP address into the sockaddr

It is already in network byte order

*/

memcpy(&server.sin_addr.s_addr, hp->h_addr, hp->h_length);

/* establish the server port number – we must use network byte order! */

server.sin_port = htons(atoi(argv[2]));

command[0] = atof(argv[3]);

st = 0;

goal = 1;

while(n <n_iterations){

p_st = st;

sendto(sk,command,sizeof(command),0,(structsockaddr*) &server,sizeof(server));

recvfrom(sk,state,sizeof(state),0,NULL,NULL);

printf(“%d\n”,(int) state[1000]);

st = state[(int) state[1000]];

outoutputstruct = new_command(command[0], st, p_st, state, goal);

command[0] = outputstruct.cmd;

goal = outputstruct.g;

if(goal == 4){

break;

}

n = n + 1;

}

}

plot.py

importmatplotlib.pyplot as plt

importcsv

x = []

y = []

with open(‘results.txt’,’r’) as csvfile:

plots = csv.reader(csvfile, delimiter=’ ‘)

for row in plots:

x.append(row[0])

y.append(row[1])

plt.plot(x,y, label=’Results…’)

plt.xlabel(‘Iteration Number’)

plt.ylabel(‘State’)

plt.show()

printerhead.c

#include <stdio.h>      /* standard C i/o facilities */

#include <stdlib.h>     /* needed for atoi() */

#include <unistd.h>     /* defines STDIN_FILENO, system calls,etc */

#include <sys/types.h>  /* system data type definitions */

#include <sys/socket.h> /* socket specific definitions */

#include <netinet/in.h> /* INET constants and stuff */

#include <arpa/inet.h>  /* IP address conversion stuff */

#include <netdb.h>      /* gethostbyname */

#include <time.h>

#if defined (WIN32) || defined (WIN64)

#include <windows.h>

#define WAIT() Sleep(10)

#else

#include <unistd.h>

#define WAIT() sleep(0.01)

#endif

#define MAXBUF 1024

#define min 2

#define max 5

structsockaddr_in server;

structsockaddr_in remote;

FILE *fichier = NULL;

intld;

intlen,n;

float state[1001], t, t_cur, t_init, y_state;

intt_prev, dt;

float command[1];

//for saturation

float saturate(float c){

if(c == -1 || c == 0 || c == 1){

return c;

}else{

return 0;

}

}

//generator of random floats in [a/t ; b*t]

float generate(int a, int b, int t){

return a/t + (rand()/(float)RAND_MAX)*(b*t – a/t);

}

//Function managing the behaviour of the system

void process(intt_prev){

floatwt, s;

//generating the noise

wt = generate(0,10,1)-5;

if(wt< 0){

wt = -1;

}else{

wt = 1;

}

//printf(“%f\n”, wt);

//s = generate(0,2,1) – 1;

y_state = y_state + command[0] + wt/100;

state[t_prev] = state[t_prev-1] + y_state;

//sendto(ld,state,t_prev,0,(structsockaddr *)&remote,len);

sendto(ld,state,sizeof(state),0,(structsockaddr *)&remote,len);

}

voidget_command(){

/* read a datagram from the socket (put result in angle) */

n=recvfrom(ld,command,sizeof(command),0,(structsockaddr *)&remote,&len);

/* print out the address of the sender */

//printf(“Got a datagram from %s port %d \n”,inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));

command[0] = saturate(command[0]);

}

/* server main routine */

int main() {

srand(time(NULL));

int length;

state[0] = 0;

state[1000] = 0;

y_state = 0;

/* need to know how big address struct is, len must be set before the

call to recvfrom!!! */

len = sizeof(remote);

/* creation des 3 sockets du serveur

IP protocol family (PF_INET)

UDP protocol (SOCK_DGRAM)

*/

if ((ld = socket( PF_INET, SOCK_DGRAM, 0 )) < 0) {

printf(“Problem creating socket\n”);

exit(1);

}

/* establish our address

address family is AF_INET

our IP address is INADDR_ANY (any of our IP addresses)

the port number is assigned by the kernel

*/

server.sin_family = AF_INET;

server.sin_addr.s_addr = htonl(INADDR_ANY);

server.sin_port = htons(0);

if (bind(ld, (structsockaddr *) &server, sizeof(server))<0) {

printf(“Problem binding socket\n”);

exit(0);

}

/* find out what port we were assigned and print it out */

length = sizeof( server );

if (getsockname(ld, (structsockaddr *) &server, &length)<0) {

printf(“Error getsockname\n”);

exit(1);

}

/* port number’s are network byte order, we have to convert to

host byte order before printing !

*/

printf(“The server UDP port number is %d\n”,ntohs(server.sin_port));

//t_prev = (float) clock()/CLOCKS_PER_SEC;

t_prev = 0;

dt = 1;

fichier = fopen(“results.txt”, “w+”);

fprintf(fichier, “%d %f\n”, t_prev, state[0]);

fclose(fichier);

while(1){

get_command();

//For REALTIME

/*

WAIT();

t_cur = (float) clock()/CLOCKS_PER_SEC;

dt = (t_cur – t_prev) + 0.01;

printf(“dt = %f\n”, dt);

t_prev = t_cur;

*/

//t_prev = t_prev + dt;

state[1000] = state[1000] + dt;

t_prev = (int) state[1000];

process(t_prev);

fichier = fopen(“results.txt”, “a”);

fprintf(fichier, “%d %f\n”, t_prev, state[t_prev]);

fclose(fichier);

}

return(0);

}

Solution

controller.c

#include <stdio.h>      /* standard C i/o facilities */

#include <stdlib.h>     /* needed for atoi() */

#include <unistd.h>     /* defines STDIN_FILENO, system calls,etc */

#include <sys/types.h>  /* system data type definitions */

#include <sys/socket.h> /* socket specific definitions */

#include <netinet/in.h> /* INET constants and stuff */

#include <arpa/inet.h>  /* IP address conversion stuff */

#include <netdb.h>      /* gethostbyname */

#include <string.h>

#define n_iterations 200

intsk; /* socket id */

intt_prev, i;

int goal;

structsockaddr_in server;

structhostent *hp;

float state[1001];

float command[1];

floatst, p_st;

typedefstruct {

int g;

floatcmd;

} out;

//Funtion for the command

outnew_command(float old_command, float current_state, float previous_state, float state[1001], int goal){

intidx = state[1000];

out output;

output.g = goal;

if(idx>= 20){

for(i=idx-20;i<idx;i++){

if(output.g == 1){

if(state[i]<9 || state[i]>11){

break;

}

if(i==idx-1){

output.g = 2; // 2nd Task

printf(“task 1 complete\n”);

}

}else if(output.g == 2){

if(state[i]<4 || state[i]>6){

break;

}

if(i==idx-1){

output.g = 3; // 3rd Task

printf(“task 2 complete\n”);

}

}else if(output.g == 3){

if(state[i]<-1 || state[i]>1){

break;

}

if(i==idx-1){

output.g = 4; // Task complete!

printf(“task 3 complete\n”);

printf(“Total iteration number: %f\n”, state[1000]);

}

}

}

}

// state[1000] is the iteration number

/*

*

*

* TYPE YOUR FUNCTION HERE TO COMPUTES THE NEW COMMAND

*

*

output.cmd = ???;

*/

float diff = current_state – previous_state;

intint_diff = 0;

if (diff > 0.5)

int_diff = 1;

if (diff < -0.5)

int_diff = -1;

//intint_diff = diff >0 ?1 : -1;

if (goal == 1) {

if (current_state< 9.5 || previous_state< 8.5) {

output.cmd = (diff > 0.95) ? -1 : 1;

} else if (current_state> 10.25) {

output.cmd = -1;

} else {

output.cmd = -int_diff;

}

} else if (goal == 2) {

if (current_state> 5.5 || previous_state> 6.5) {

output.cmd = (diff < -0.95) ?1 : -1;

} else if (current_state< 4.5) {

output.cmd = 1;

} else {

output.cmd = -int_diff;

}

} else if (goal == 3) {

if (current_state> 0.5 || previous_state> 1.5) {

output.cmd = (diff < -0.95) ?1 : -1;

} else if (current_state< -0.5) {

output.cmd = 1;

} else {

output.cmd = -int_diff;

}

}

return output;

}

int main( intargc, char **argv ) {

intj,n=0,len;

structsockaddr_in remote;

/* need to know how big address struct is, len must be set before the

call to recvfrom!!! */

len = sizeof(remote);

/* Make sure we have the right number of command line args */

if (argc!=4) {

printf(“Usage: %s <server name><port number><initial command value>\n”,argv[0]);

exit(0);

}

/* create socket

IP protocol family (PF_INET)

UDP (SOCK_DGRAM)

*/

if ((sk = socket( PF_INET, SOCK_DGRAM, 0 )) < 0)

{

printf(“Problem creating socket 1\n”);

exit(1);

}

server.sin_family = AF_INET;

if ((hp = gethostbyname(argv[1]))==0) {

printf(“Invalid or unknown host\n”);

exit(1);

}

/* copy the IP address into the sockaddr

It is already in network byte order

*/

memcpy(&server.sin_addr.s_addr, hp->h_addr, hp->h_length);

/* establish the server port number – we must use network byte order! */

server.sin_port = htons(atoi(argv[2]));

command[0] = atof(argv[3]);

st = 0;

goal = 1;

while(n <n_iterations){

p_st = st;

sendto(sk,command,sizeof(command),0,(structsockaddr*) &server,sizeof(server));

recvfrom(sk,state,sizeof(state),0,NULL,NULL);

printf(“%d\n”,(int) state[1000]);

st = state[(int) state[1000]];

outoutputstruct = new_command(command[0], st, p_st, state, goal);

command[0] = outputstruct.cmd;

goal = outputstruct.g;

if(goal == 4){

break;

}

n = n + 1;

}

}