Advertisement
Guest User

Untitled

a guest
Dec 4th, 2014
340
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.67 KB | None | 0 0
  1. #include <Servo.h>
  2. #include <SPI.h>
  3. #include <nRF24L01.h>
  4. #include <RF24.h>
  5. #include <Wire.h>
  6.  
  7. /* Pin definitions */
  8. #define LEFT_DRIVE_MOTOR_CONTROLPIN_1 9
  9. #define LEFT_DRIVE_MOTOR_CONTROLPIN_2 10
  10. #define LEFT_DRIVE_MOTOR_SPEEDPIN 8
  11.  
  12. #define RIGHT_DRIVE_MOTOR_CONTROLPIN_1 12
  13. #define RIGHT_DRIVE_MOTOR_CONTROLPIN_2 11
  14. #define RIGHT_DRIVE_MOTOR_SPEEDPIN 13
  15.  
  16. #define WATER_SERVO_CONTROLPIN_1 3
  17. #define WATER_SERVO_CONTROLPIN_2 4
  18. #define WATER_SERVO_SPEEDPIN 2
  19.  
  20. #define FIRE_SERVO_CONTROLPIN_1 6
  21. #define FIRE_SERVO_CONTROLPIN_2 5
  22. #define FIRE_SERVO_SPEEDPIN 7
  23.  
  24. #define TOWER_X_PIN 26
  25. #define TOWER_Y_PIN 25
  26.  
  27. #define PILOT_FLAME 24
  28.  
  29. #define PRESSURE_SENSOR_PIN A4
  30. #define COMPRESSOR_RELAY_PIN 41
  31.  
  32. #define RADIO_CE_PIN 49
  33. #define RADIO_CSN_PIN 53
  34. /*
  35. SCK  52
  36. MOSI 51
  37. MISO 50
  38. */
  39.  
  40. #define RGB_LED_RED_PIN A0
  41. #define RGB_LED_GREEN_PIN A1
  42. #define RGB_LED_BLUE_PIN A2
  43.  
  44.  
  45. /* variables used by i2c protcol */
  46. #define SLAVE_ADDRESS 0x04
  47. #define ST_IDLE 0x1
  48. #define ST_HEAD1_OK 0x2
  49. #define ST_HEAD2_OK 0x3
  50. #define ST_HEADER_OK 0x4
  51. #define ST_X_READ 0x5
  52.  
  53. #define CAMERA_COORDINATES_X_THRESHOLD 40
  54. #define CAMERA_COORDINATES_Y_THRESHOLD 10
  55. #define AUTO_TURN_SPEED 255
  56. #define AUTO_DRIVE_SPEED 255
  57. #define AUTO_EXTINGUISH_THRESHOLD 40
  58. #define AUTO_TOWER_Y_MOVE_STEPS 127
  59. #define AUTO_EXTINGUISH_TIME 2000
  60.  
  61. //enum of modes
  62. enum Mode {
  63.   WATERMODE,
  64.   FIREMODE,
  65.   AUTOMODE
  66. };
  67.  
  68. /*
  69.   Class to control the motors
  70. */
  71. class MotorControl {
  72.   private:
  73.     int controlPin1, controlPin2, speedPin;
  74.   public:
  75.     MotorControl(int p1, int p2, int p3) {
  76.       controlPin1 = p1;
  77.       controlPin2 = p2;
  78.       speedPin = p3;
  79.  
  80.       pinMode(controlPin1, OUTPUT);
  81.       pinMode(controlPin2, OUTPUT);
  82.       pinMode(speedPin, OUTPUT);
  83.     }
  84.     void setSpeed(int s) {
  85.       //if speed is set to 0, no further calculations is needed
  86.       if(s == 0) {
  87.         analogWrite(speedPin, 0);
  88.         return;
  89.       }
  90.       //set the control pins to (0, 1) or (1, 0) based on the direction
  91.       digitalWrite(controlPin1, s > 0);
  92.       digitalWrite(controlPin2, s < 0);
  93.  
  94.       s = abs(s); //direction is handled by the control pins
  95.       s = map(s, 0, 512, 60, 255); //map the speed value from 0-512 to 60-255. 60 is the minimum speed for the motors to start
  96.       s = constrain(s, 60, 255); //constrain the variable
  97.       analogWrite(speedPin, s); //write it to the speed control
  98.     }
  99. };
  100.  
  101. //The lego servos use a similar control to the motors
  102. class BinaryMotorControl : protected MotorControl {
  103.   private:
  104.     //two states given
  105.     int states[2];
  106.   public:
  107.     //initialize the servo with the states
  108.     BinaryMotorControl(int s1, int s2, int p1, int p2, int p3) : MotorControl(p1, p2, p3) {
  109.       states[0] = s1;
  110.       states[1] = s2;
  111.     }
  112.     void setState(boolean state) {
  113.       setSpeed(states[state]);
  114.     }
  115. };
  116.  
  117. /* Class to control the servos */
  118. class JoystickServo {
  119.   private:
  120.     Servo s;
  121.     //lower and upper range, that the servo will stay within
  122.     int upperRange, lowerRange, resetPos;
  123.     //position of the servo, float so its possible to 'move' less than a step
  124.     float pos;
  125.   public:
  126.     JoystickServo(int pin, int lr, int ur, int start) {
  127.       //initialize variables and put the servo in its starting position
  128.       s.attach(pin);
  129.       resetPos = start;
  130.       pos = start;
  131.       s.write(start);
  132.       lowerRange = lr;
  133.       upperRange = ur;
  134.     }
  135.     //move the servo, 512 being 1 step
  136.     void move(int value) {
  137.       pos += value/512.0;
  138.       if(pos < lowerRange) pos = lowerRange;
  139.       else if(pos > upperRange) pos = upperRange;
  140.       s.write(pos);
  141.     }
  142.     int getPos() {
  143.       //get the current position of the servo
  144.       return pos;
  145.     }
  146.     void reset() {
  147.       //put the servo back to its starting position
  148.       pos = resetPos;
  149.       s.write(pos);
  150.     }
  151. };
  152.  
  153. /* Servo controller with two states */
  154. class ToggleServo {
  155.   private:
  156.     int states[2];
  157.     //variables to slow down the movement of the servo
  158.     float pos;
  159.     boolean moving;
  160.     Servo servo;
  161.   public:
  162.     ToggleServo(int pin, int s1, int s2) {
  163.       servo.attach(pin);
  164.       servo.write(s1);
  165.       moving = 0;
  166.       states[0] = s1;
  167.       states[1] = s2;
  168.     }
  169.     void setState(boolean s) {
  170.       //slow down only one direction, reverting to start position is instant
  171.       if(s) {
  172.         moving = true;
  173.       } else {
  174.         servo.write(states[0]);
  175.         pos = states[0];
  176.       }
  177.     }
  178.     void tick() {
  179.       //if the servo is supposed to move
  180.       if(moving) {
  181.         //if the servo has not yet reached its goal position
  182.         if(pos > states[1]) pos -= 0.8;
  183.         else {
  184.           //if it has, stop 'moving'
  185.           pos = states[1];
  186.           moving = 0;
  187.         }
  188.         //write the position to the servo
  189.         servo.write(pos);
  190.       }
  191.     }
  192.     boolean isOn() {
  193.       //check wether the servo is on or off
  194.       return pos == states[1];
  195.     }
  196. };
  197.  
  198. /*
  199.   Class to maintain the pressure in the tanks. Fully automatic
  200. */
  201. class PressureSustainer {
  202.   private:
  203.     float upper, lower, bar, avg;
  204.     int count, sensorPin, relayPin;
  205.   public:
  206.     PressureSustainer(float b, float t, int s, int r) {
  207.       upper = b;
  208.       lower = b - t;
  209.       bar = 0.0;
  210.       setState(0);
  211.       count = 10;
  212.       avg = 0.0;
  213.  
  214.       sensorPin = s;
  215.       relayPin = r;
  216.       pinMode(r, OUTPUT);
  217.       digitalWrite(r, 1);
  218.     }
  219.     void tick() {
  220.       //map the values from the sensor (0.5V - 4.5V) to the measure range (0bar - 12bar)
  221.       bar = map(analogRead(sensorPin), 102, 921, 0, 1200) / 100.0;
  222.  
  223.       //count the 10 last measurements
  224.       avg += bar;
  225.       count--;
  226.       //when 10 measurements are taken
  227.       if(count <= 0) {
  228.         avg /= 10.0; //calculate the average
  229.         if(avg < lower) setState(1); //if the average is lower than the goal - threshold, start compressor
  230.         else if(avg > upper) setState(0); //if its higher than goal, stop the compressor
  231.         count = 10; //start count over
  232.         avg = 0.0;
  233.       }
  234.     }
  235.     void setState(bool state) {
  236.       //turn compressor on/off
  237.       digitalWrite(relayPin, !state);
  238.     }
  239.     float getBar() {
  240.       //return the current bar value
  241.       return bar;
  242.     }
  243.     int getValue() {
  244.       //return value of the sensor
  245.       return analogRead(sensorPin);
  246.     }
  247. };
  248.  
  249. //function to decompress the data received
  250. void byteArrToIntArr(byte arr[], int byteSize, int keep[], int data[], int dataSize) {
  251.   uint64_t temp = 0;
  252.   for(int i = 0; i < byteSize; i++) temp = (temp << 8) | arr[i]; //push the byte into the temporary 64b variable
  253.   for(int i = dataSize - 1; i >= 0; i--) {
  254.     data[i] = (int)(temp & ((1 << keep[i]) - 1)); //take x number of bits and put them into its own variable
  255.     temp >>= keep[i];
  256.   }
  257. }
  258.  
  259.  
  260. //pipe for communication
  261. const uint64_t pipe = 0xF0F0F0F0AALL;
  262.  
  263.  
  264. //pointers as not all arduino stuff are ready yet (pinMode eg.)
  265. ToggleServo *pilotFlame;
  266. JoystickServo *towerX;
  267. JoystickServo *towerY;
  268. MotorControl *leftDrive;
  269. MotorControl *rightDrive;
  270. BinaryMotorControl *waterValve;
  271. BinaryMotorControl *fireValve;
  272.  
  273. PressureSustainer *pressureSustainer;
  274.  
  275. RF24 radio(RADIO_CE_PIN, RADIO_CSN_PIN);
  276.  
  277. //communication variables
  278. int bytesReceived = 6;
  279. byte arrayReceived[6];
  280.  
  281. //the data received, how many bits to store and what they are
  282. int data[8];
  283. int bitsToKeep[] = {10, 10, 1, 10, 10, 1, 2, 1};
  284. enum Data {
  285.   J1X,
  286.   J1Y,
  287.   PILOTFLAME,
  288.   J2X,
  289.   J2Y,
  290.   TRIGGER,
  291.   MODE
  292. };
  293.  
  294. //initializing variables
  295. int leftMotorSpeed, rightMotorSpeed, x, y;
  296. int state = ST_IDLE; //I2C state
  297. int cameraCoordinates[2];
  298. bool newCoordinatesReceived, flameFound;
  299. Mode mode;
  300.  
  301. //array of the led pins, their colours in relation to the modes (water, fire, auto)
  302. byte leds[] = {RGB_LED_BLUE_PIN, RGB_LED_RED_PIN, RGB_LED_GREEN_PIN};
  303.  
  304.  
  305.  
  306.  
  307. void setup() {
  308.   //start up radio and set payload size
  309.   radio.begin();
  310.   radio.setPayloadSize(6);
  311.   radio.openReadingPipe(1, pipe);
  312.   radio.startListening();
  313.  
  314.   //start up I2C communication
  315.   Wire.begin(SLAVE_ADDRESS);
  316.   Wire.onReceive(receiveData);
  317.   newCoordinatesReceived = 0;
  318.   flameFound = 0;
  319.  
  320.   //initialize classes with given parameters
  321.   pilotFlame = new ToggleServo(PILOT_FLAME, 108, 55);
  322.   towerX = new JoystickServo(TOWER_X_PIN, 15, 120, 84);
  323.   towerY = new JoystickServo(TOWER_Y_PIN, 10, 110, 50);
  324.   leftDrive = new MotorControl(LEFT_DRIVE_MOTOR_CONTROLPIN_1, LEFT_DRIVE_MOTOR_CONTROLPIN_2, LEFT_DRIVE_MOTOR_SPEEDPIN);
  325.   rightDrive = new MotorControl(RIGHT_DRIVE_MOTOR_CONTROLPIN_1, RIGHT_DRIVE_MOTOR_CONTROLPIN_2, RIGHT_DRIVE_MOTOR_SPEEDPIN);
  326.   waterValve = new BinaryMotorControl(0, 150, WATER_SERVO_CONTROLPIN_1, WATER_SERVO_CONTROLPIN_2, WATER_SERVO_SPEEDPIN);
  327.   fireValve = new BinaryMotorControl(0, 150, FIRE_SERVO_CONTROLPIN_1, FIRE_SERVO_CONTROLPIN_2, FIRE_SERVO_SPEEDPIN);
  328.   pressureSustainer = new PressureSustainer(3, 0.3, PRESSURE_SENSOR_PIN, COMPRESSOR_RELAY_PIN);
  329.  
  330.   //set the mode for the led pins
  331.   for(int i = 0; i < sizeof(leds); i++) pinMode(leds[i], OUTPUT);
  332. }
  333.  
  334. void loop() {
  335.   mode = AUTOMODE;
  336.   //set automode as standard
  337.   while(radio.available()) {
  338.     //if radio is received, read it
  339.     radio.read(arrayReceived, bytesReceived);
  340.     //translate the byte string received to an int array
  341.     byteArrToIntArr(arrayReceived, bytesReceived, bitsToKeep, data, 8);
  342.  
  343.     //subtract 511 to obtain position data with 0 as origa
  344.     data[J1X] -= 511;
  345.     data[J1Y] -= 511;
  346.     data[J2X] -= 511;
  347.     data[J2Y] -= 511;
  348.    
  349.     //set the mode from the radio signal  
  350.     mode = data[MODE];
  351.     //if in automatic mode, break out of manual control loop
  352.     if(mode == AUTOMODE) break;
  353.  
  354.  
  355.     if(mode == WATERMODE) {
  356.       //if in watermode, ensure firevalve is closed
  357.       fireValve->setState(0);
  358.       //ensure pilot flame is off
  359.       pilotFlame->setState(0);
  360.       //set the status of the watervalve to the value of the trigger send over radio
  361.       waterValve->setState(data[TRIGGER]);
  362.     } else if(mode == FIREMODE) {
  363.       //if in firemode, ensure water valve is closed
  364.       waterValve->setState(0);
  365.       //turn on pilot flame if depending on radio signal
  366.       pilotFlame->setState(data[PILOTFLAME]);
  367.       if(pilotFlame->isOn()) {
  368.         //if the pilot flame is on, set firevalve to the status of the trigger signal
  369.         fireValve->setState(data[TRIGGER]);
  370.       }
  371.     }
  372.  
  373.     //variables for computation of drive engine speed
  374.     x = data[J1X];
  375.     y = data[J1Y];
  376.  
  377.     //set both engines to have speed depending on y-axis on the joystick (-512, 512)
  378.     leftMotorSpeed = y;
  379.     rightMotorSpeed = y;
  380.  
  381.     //adding the turn value (x-axis) to the side in question
  382.     if(x > 0) leftMotorSpeed += x;
  383.     else rightMotorSpeed -= x;
  384.  
  385.     //setting the drive speeds
  386.     leftDrive->setSpeed(leftMotorSpeed);
  387.     rightDrive->setSpeed(rightMotorSpeed);
  388.  
  389.     //moving the tower servos depending on input from ther ight joystick
  390.     towerX->move(-data[J2X]);
  391.     towerY->move(data[J2Y]);
  392.   }
  393.   /* Make sure the correct led is lit, depending on state */
  394.   for(int i = 0; i < sizeof(leds); i++) {
  395.     if(i == mode) digitalWrite(leds[i], 1);
  396.     else digitalWrite(leds[i], 0);
  397.   }
  398.  
  399.   if(mode == AUTOMODE) {
  400.     //if pilot flame is on, turn it off
  401.     if(pilotFlame->getState()) pilotFlame->setState(0);
  402.  
  403.     //if a flame is directly in front
  404.     if(flameFound) {
  405.       if(newCoordinatesReceived)   else {
  406.  
  407.         //the flame is extinguished, set that state, turn of water valve and reset the tower position
  408.         flameFound = 0;
  409.         waterValve->setState(0);
  410.         towerX->reset();
  411.         towerY->reset();
  412.       }
  413.     } else if(!newCoordinatesReceived) {
  414.       //no new coordinates from the camera, rotate on the spot (until flame is found)
  415.       leftDrive->setSpeed(-AUTO_TURN_SPEED);
  416.       rightDrive->setSpeed(AUTO_TURN_SPEED);
  417.     } else {
  418.       //the robot sees the flame
  419.       if(abs(cameraCoordinates[1]) > CAMERA_COORDINATES_Y_THRESHOLD) {
  420.         //if the camera is out of the Y-axis thershold, move the tower along that axis
  421.         towerY->move(AUTO_TOWER_Y_MOVE_STEPS * -cameraCoordinates[1]/100);
  422.       }
  423.       if(abs(cameraCoordinates[0]) > CAMERA_COORDINATES_X_THRESHOLD) {
  424.         //if the flame is outside the X-axis thershold, rotate the robot towards it
  425.         int modifier = cameraCoordinates[0] < 0 ? -1 : 1;
  426.         leftDrive->setSpeed(AUTO_TURN_SPEED * modifier);
  427.         rightDrive->setSpeed(-AUTO_TURN_SPEED * modifier);
  428.  
  429.       } else {
  430.         //the flame is within the x-axis threshold
  431.         if(towerY->getPos() > AUTO_EXTINGUISH_THRESHOLD) {
  432.           //check the position of the tower along y axis, if its above the the set 'angle' (servo position), drive forward
  433.           leftDrive->setSpeed(AUTO_DRIVE_SPEED);
  434.           rightDrive->setSpeed(AUTO_DRIVE_SPEED);
  435.         } else {
  436.           /*
  437.               the tower is within range of the flame (checked by the tower servo position) and turns off the drive engines.
  438.               it then says the starts extinguishing the flame
  439.           */
  440.           flameFound = 1;
  441.           leftDrive->setSpeed(0);
  442.           rightDrive->setSpeed(0);
  443.         }
  444.       }
  445.     }
  446.  
  447.  
  448.  
  449.  
  450.   }
  451.   //if the pilot flame is supposed to move, do so
  452.   pilotFlame->tick();
  453.   //make sure the pressure is within its bounds
  454.   pressureSustainer->tick();
  455.   //delay 10ms because arduino
  456.   delay(10);
  457.  
  458. }
  459.  
  460. /* callback function for I2C communication */
  461. void receiveData(int byteCount){
  462.   while (Wire.available()) {
  463.     //while theres bytes to read (not package)
  464.     int number = Wire.read();
  465.     //check the current state of the protocol
  466.     switch (state)
  467.     {
  468.     case ST_IDLE:
  469.       //check the first byte wether it matches a header or not
  470.       if (number == 0x5C)
  471.           state = ST_HEAD1_OK;
  472.       break;
  473.       //check second byte to see if it matches
  474.     case ST_HEAD1_OK:
  475.       if (number == 0xF3)
  476.           state = ST_HEAD2_OK;
  477.       else
  478.           state = ST_IDLE;
  479.       break;
  480.     case ST_HEAD2_OK:
  481.       //check wether the third header matches
  482.       if (number == 0x0A)
  483.           state = ST_HEADER_OK;
  484.       else
  485.           state = ST_IDLE;
  486.       break;
  487.     case ST_HEADER_OK:
  488.       //read the 4th byte, flame coordinates in x direction
  489.       cameraCoordinates[0] = number - 127;
  490.       state = ST_X_READ;
  491.       break;
  492.     case ST_X_READ:
  493.       //read the 5th byte, flame coordinates in y direction
  494.       cameraCoordinates[1] = number - 127;
  495.       //if both coordinates are not 127 (value if no flame is detected), new coordinates are received
  496.       if(cameraCoordinates[0] < 127 && cameraCoordinates[1] < 127) newCoordinatesReceived = 1;
  497.       //else no new coordinates
  498.       else newCoordinatesReceived = 0;
  499.       state = ST_IDLE;
  500.       break;
  501.     default:
  502.       break;
  503.     }
  504.   }
  505. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement