Telescope motorised focuser based on the moonlite protocol, indilib's indi_monlite_focuser compliant. WIP

Committer:
rakware
Date:
Sun Aug 05 09:19:46 2018 +0000
Revision:
8:ccfbd168f077
Parent:
7:30dcdf917330
using Ticker to set motor speed

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rakware 2:c75920ffd4b1 1 #include "mbed.h" //uses https://github.com/ARMmbed/mbed-os/
rakware 2:c75920ffd4b1 2
rakware 3:20b077586e4e 3 DigitalOut led(LED1); //board led, just for fun
rakware 3:20b077586e4e 4
rakware 2:c75920ffd4b1 5 Serial pc(USBTX, USBRX); // tx, rx pc control over usb
rakware 0:c990fafbe0fc 6
rakware 3:20b077586e4e 7 uint16_t gn = 0; //position to move to
rakware 3:20b077586e4e 8 uint16_t gp = 0; //current position
rakware 3:20b077586e4e 9 uint16_t temperature = 255; //hardcoded for now //TODO
rakware 3:20b077586e4e 10
rakware 8:ccfbd168f077 11 bool move = false;
rakware 2:c75920ffd4b1 12
rakware 3:20b077586e4e 13 uint16_t step_delay = 256;
rakware 5:8965c2919afb 14
rakware 5:8965c2919afb 15 //minimum motor speed that will get doubled 5 times to result maximum motor speed
rakware 8:ccfbd168f077 16 //eg: for a value of 16 there will be 5 speeds as follows 16*1,16*2,16*4,16*8,16*16
rakware 8:ccfbd168f077 17 //eg: for a value of 16 there will be 5 speeds as follows 16,32,64,128,256
rakware 8:ccfbd168f077 18 uint8_t min_motor_pps = 16; //TODO use max pps since it might be more intuitive?
rakware 4:2235d6d01ca5 19
rakware 3:20b077586e4e 20
rakware 3:20b077586e4e 21 char ml_in[256];
rakware 3:20b077586e4e 22 uint8_t idx = 0;
rakware 3:20b077586e4e 23
rakware 8:ccfbd168f077 24 Thread serial_thread, motor_thread;
rakware 8:ccfbd168f077 25 Ticker m_speed;
rakware 0:c990fafbe0fc 26
rakware 2:c75920ffd4b1 27 void led_blink()
rakware 2:c75920ffd4b1 28 {
rakware 2:c75920ffd4b1 29 while (true) {
rakware 2:c75920ffd4b1 30 led = !led;
rakware 2:c75920ffd4b1 31 wait(1);
rakware 2:c75920ffd4b1 32 }
rakware 2:c75920ffd4b1 33 }
rakware 2:c75920ffd4b1 34
rakware 0:c990fafbe0fc 35
rakware 5:8965c2919afb 36 //motor control with MP6500 https://www.pololu.com/product/2968
rakware 5:8965c2919afb 37 //aproximate formula for motor current control pwm.pulsewidth% = (motor_rated_current_in_amps-2.2)/-2.079, so for our 330ma motor we use pw = (0.330-2.2)/-2.079
rakware 5:8965c2919afb 38 // https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures , 1 kHz or greater, I2 set to low
rakware 4:2235d6d01ca5 39 //D2,D3,D4,D5,D6,D7,D8,D9 - DIR, STEP, SLP, I2, I1, MS2, MS1, EN
rakware 4:2235d6d01ca5 40
rakware 4:2235d6d01ca5 41 DigitalOut dir(D2);
rakware 4:2235d6d01ca5 42 DigitalOut step(D3);
rakware 4:2235d6d01ca5 43 DigitalOut slp(D4); //pull high to enable operation
rakware 5:8965c2919afb 44 DigitalOut i2(D5); //set low to enable pwm power control
rakware 4:2235d6d01ca5 45 PwmOut i1(D6); //MP6500 power limit control
rakware 8:ccfbd168f077 46 DigitalOut ms2(D7); //D7 and D8 are PC_14 and PC_15 N/C oscillator pins, hence this is full step only //TODO
rakware 4:2235d6d01ca5 47 DigitalOut ms1(D8); //set low for FULL or high for HALF, only use MS1 to be moonlite compliant ?
rakware 4:2235d6d01ca5 48 DigitalOut en(D9); //pulled low by the motor driver, default enables operation
rakware 4:2235d6d01ca5 49
rakware 5:8965c2919afb 50 float motor_max_amps = 0.33f;
rakware 4:2235d6d01ca5 51
rakware 7:30dcdf917330 52 float pw = (motor_max_amps-2.2f)/-2.079f; //https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures
rakware 0:c990fafbe0fc 53
rakware 4:2235d6d01ca5 54 void mp6500() //TODO enable/disable motor
rakware 4:2235d6d01ca5 55 {
rakware 4:2235d6d01ca5 56 dir = 0;
rakware 4:2235d6d01ca5 57 step = 0;
rakware 4:2235d6d01ca5 58 slp = 1;
rakware 4:2235d6d01ca5 59 i2 = 0;
rakware 4:2235d6d01ca5 60 i1.period(0.001f); //1kHz period
rakware 8:ccfbd168f077 61 i1.write(1.0f); //start with lowest power since we're idle
rakware 4:2235d6d01ca5 62 ms2 = 0;
rakware 5:8965c2919afb 63 ms1 = 1;
rakware 4:2235d6d01ca5 64 en = 0;
rakware 4:2235d6d01ca5 65 }
rakware 4:2235d6d01ca5 66
rakware 4:2235d6d01ca5 67
rakware 8:ccfbd168f077 68 void m_step()
rakware 3:20b077586e4e 69 {
rakware 2:c75920ffd4b1 70
rakware 8:ccfbd168f077 71 //while (true) {
rakware 3:20b077586e4e 72
rakware 3:20b077586e4e 73 if(move) {
rakware 5:8965c2919afb 74
rakware 5:8965c2919afb 75 i1.write(pw); //set defined current motor while moving
rakware 5:8965c2919afb 76
rakware 3:20b077586e4e 77 if(gp > gn) {
rakware 3:20b077586e4e 78
rakware 4:2235d6d01ca5 79 dir = 0;
rakware 5:8965c2919afb 80 wait_us(1);
rakware 5:8965c2919afb 81 //led = !led;
rakware 4:2235d6d01ca5 82 step = !step;
rakware 5:8965c2919afb 83 wait_us(1); //mp6500
rakware 5:8965c2919afb 84 //led = !led;
rakware 4:2235d6d01ca5 85 step = !step;
rakware 5:8965c2919afb 86 wait_us(1);
rakware 8:ccfbd168f077 87 //https://os.mbed.com/docs/v5.9/mbed-os-api-doxy/mbed__wait__api_8h_source.html use Thread::wait()?
rakware 8:ccfbd168f077 88 //wait((step_delay/1.024)/min_motor_pps/250);
rakware 3:20b077586e4e 89 gp--;
rakware 3:20b077586e4e 90
rakware 3:20b077586e4e 91 } else if (gp < gn) {
rakware 0:c990fafbe0fc 92
rakware 4:2235d6d01ca5 93 dir = 1;
rakware 5:8965c2919afb 94 wait_us(1);
rakware 5:8965c2919afb 95 //led = !led;
rakware 4:2235d6d01ca5 96 step = !step;
rakware 5:8965c2919afb 97 wait_us(1);
rakware 5:8965c2919afb 98 //led = !led;
rakware 4:2235d6d01ca5 99 step = !step;
rakware 5:8965c2919afb 100 wait_us(1);
rakware 8:ccfbd168f077 101 //wait((step_delay/1.024)/min_motor_pps/250);
rakware 3:20b077586e4e 102 gp++;
rakware 3:20b077586e4e 103
rakware 3:20b077586e4e 104 } else {
rakware 3:20b077586e4e 105
rakware 4:2235d6d01ca5 106 step = dir = 0;
rakware 5:8965c2919afb 107 wait_us(1);
rakware 5:8965c2919afb 108
rakware 6:c74fa5932b21 109 i1.write(1.0f); //set minimum controller power while holding, keeps motor cool and still provides a nice holding torque, ~120ma
rakware 4:2235d6d01ca5 110
rakware 3:20b077586e4e 111 move = false;
rakware 0:c990fafbe0fc 112
rakware 3:20b077586e4e 113 }
rakware 3:20b077586e4e 114
rakware 3:20b077586e4e 115 }
rakware 3:20b077586e4e 116
rakware 8:ccfbd168f077 117 //}
rakware 3:20b077586e4e 118
rakware 3:20b077586e4e 119 }
rakware 3:20b077586e4e 120
rakware 3:20b077586e4e 121
rakware 3:20b077586e4e 122
rakware 3:20b077586e4e 123 //http://indilib.org/media/kunena/attachments/1/HighResSteppermotor107.pdf
rakware 2:c75920ffd4b1 124 void read_serial()
rakware 0:c990fafbe0fc 125 {
rakware 8:ccfbd168f077 126 while(true){
rakware 8:ccfbd168f077 127 if(pc.readable()) {
rakware 0:c990fafbe0fc 128 char c = pc.getc();
rakware 0:c990fafbe0fc 129
rakware 0:c990fafbe0fc 130 switch (c) {
rakware 0:c990fafbe0fc 131 case '#':
rakware 0:c990fafbe0fc 132
rakware 0:c990fafbe0fc 133 switch (ml_in[0]) {
rakware 0:c990fafbe0fc 134 case 'C': //N/A Initiate a temperature conversion; the conversion process takes a maximum of 750 milliseconds. The value returned by the :GT# command will not be valid until the conversion process completes.
rakware 2:c75920ffd4b1 135 break; //TODO
rakware 0:c990fafbe0fc 136 case 'F':
rakware 0:c990fafbe0fc 137 switch (ml_in[1]) {
rakware 0:c990fafbe0fc 138 case 'G': //N/A Go to the new position as set by the ":SNYYYY#" command.
rakware 4:2235d6d01ca5 139 move = true; //runs motor();
rakware 0:c990fafbe0fc 140 break;
rakware 0:c990fafbe0fc 141 case 'Q': //N/A Immediately stop any focus motor movement.
rakware 3:20b077586e4e 142 move = false;
rakware 0:c990fafbe0fc 143 break;
rakware 0:c990fafbe0fc 144 default:
rakware 0:c990fafbe0fc 145 break;
rakware 0:c990fafbe0fc 146 }
rakware 0:c990fafbe0fc 147 break;
rakware 0:c990fafbe0fc 148
rakware 0:c990fafbe0fc 149 case 'G':
rakware 0:c990fafbe0fc 150 switch (ml_in[1]) {
rakware 0:c990fafbe0fc 151 case 'B': // Get the backlight value
rakware 0:c990fafbe0fc 152 pc.printf("00#");
rakware 0:c990fafbe0fc 153 break;
rakware 0:c990fafbe0fc 154 case 'C': //XX# Returns the temperature coefficient where XX is a two-digit signed (2’s complement) hex number.
rakware 0:c990fafbe0fc 155 pc.printf("02#");
rakware 0:c990fafbe0fc 156 break;
rakware 0:c990fafbe0fc 157 case 'D': //XX# Returns the current stepping delay where XX is a two-digit unsigned hex number. Valid values 02, 04, 08, 10, 20 -> stepping delay 250, 125, 63, 32, 16 pps
rakware 4:2235d6d01ca5 158 pc.printf("%02X#", 512 / step_delay); //TODO? we sleep for step_delay*step_delay_multiplier microseconds between steps
rakware 0:c990fafbe0fc 159 break;
rakware 0:c990fafbe0fc 160 case 'H': //00# OR FF# Returns "FF#" if the focus motor is half-stepped otherwise return "00#"
rakware 4:2235d6d01ca5 161 //pc.printf("00#"); //TODO
rakware 4:2235d6d01ca5 162 pc.printf("%02X#", ms1 * 255);
rakware 0:c990fafbe0fc 163 break;
rakware 0:c990fafbe0fc 164 case 'I': //00# OR 01# Returns "00#" if the focus motor is not moving, otherwise return "01#"
rakware 8:ccfbd168f077 165 pc.printf("%02X#", move);
rakware 0:c990fafbe0fc 166 break;
rakware 2:c75920ffd4b1 167 case 'N': //YYYY# Returns the new position previously set by a ":SNYYYY#" command where YYYY is a four-digit unsigned hex number
rakware 2:c75920ffd4b1 168 pc.printf("%04X#", gn); //TODO use this to move the motor
rakware 0:c990fafbe0fc 169 break;
rakware 0:c990fafbe0fc 170 case 'P': //YYYY# Returns the current position where YYYY is a four-digit unsigned hex number.
rakware 2:c75920ffd4b1 171 pc.printf("%04X#", gp); //TODO update gp with actual motor data
rakware 0:c990fafbe0fc 172 break;
rakware 0:c990fafbe0fc 173 case 'T': //YYYY# Returns the current temperature where YYYY is a four-digit signed (2’s complement) hex number.
rakware 2:c75920ffd4b1 174 pc.printf("%04X#", temperature * 2); //indi_moonlite_focuser returns the temp/2, dunno why, dont care
rakware 4:2235d6d01ca5 175 //pc.printf("0019#"); //should be 25c but is 12.5c in indi_moonlite control panel
rakware 0:c990fafbe0fc 176 break;
rakware 0:c990fafbe0fc 177 case 'V': //DD# Get the version of the firmware as a two-digit decimal number where the first digit is the major version number, and the second digit is the minor version number.
rakware 0:c990fafbe0fc 178 pc.printf("01#");
rakware 0:c990fafbe0fc 179 break;
rakware 0:c990fafbe0fc 180 default:
rakware 0:c990fafbe0fc 181 break;
rakware 0:c990fafbe0fc 182 }
rakware 0:c990fafbe0fc 183 break;
rakware 0:c990fafbe0fc 184
rakware 0:c990fafbe0fc 185 case 'S':
rakware 0:c990fafbe0fc 186 switch(ml_in[1]) {
rakware 0:c990fafbe0fc 187 case 'C': //N/A Set the new temperature coefficient where XX is a two-digit, signed (2’s complement) hex number.
rakware 2:c75920ffd4b1 188 break; //TODO
rakware 0:c990fafbe0fc 189 case 'D': //N/A Set the new stepping delay where XX is a two-digit, unsigned hex number. Valid values to send are 02, 04, 08, 10 and 20, which correspond to a stepping delay of 250, 125, 63, 32 and 16 steps per second respectively.
rakware 3:20b077586e4e 190 step_delay = 512 / strtol(ml_in + 2, NULL, 16);
rakware 8:ccfbd168f077 191 m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250);
rakware 0:c990fafbe0fc 192 break;
rakware 0:c990fafbe0fc 193
rakware 0:c990fafbe0fc 194 case 'F': //N/A Set full-step mode.
rakware 4:2235d6d01ca5 195 ms1 = 0;
rakware 0:c990fafbe0fc 196 break;
rakware 0:c990fafbe0fc 197
rakware 0:c990fafbe0fc 198 case 'H': //N/A Set half-step mode.
rakware 4:2235d6d01ca5 199 ms1 = 1;
rakware 0:c990fafbe0fc 200 break;
rakware 0:c990fafbe0fc 201
rakware 0:c990fafbe0fc 202 case 'N': //N/A Set the new position where YYYY is a four-digit unsigned hex number.
rakware 3:20b077586e4e 203 gn = strtol(ml_in + 2, NULL, 16); //read ml_in, discard 2 chars, convert to long, set gn
rakware 0:c990fafbe0fc 204 break;
rakware 0:c990fafbe0fc 205
rakware 0:c990fafbe0fc 206 case 'P': //Set the current position where YYYY is a four-digit unsigned hex number.
rakware 2:c75920ffd4b1 207 gp = strtol(ml_in + 2, NULL, 16);
rakware 0:c990fafbe0fc 208 break;
rakware 0:c990fafbe0fc 209
rakware 0:c990fafbe0fc 210 default:
rakware 0:c990fafbe0fc 211 break;
rakware 0:c990fafbe0fc 212 }
rakware 0:c990fafbe0fc 213 break;
rakware 0:c990fafbe0fc 214
rakware 0:c990fafbe0fc 215 case '+': //N/A Activate temperature compensation focusing.
rakware 0:c990fafbe0fc 216 break; //TODO
rakware 0:c990fafbe0fc 217 case '-': //N/A Disable temperature compensation focusing.
rakware 0:c990fafbe0fc 218 break; //TODO
rakware 0:c990fafbe0fc 219
rakware 0:c990fafbe0fc 220 case 'P':
rakware 0:c990fafbe0fc 221 break;
rakware 0:c990fafbe0fc 222
rakware 0:c990fafbe0fc 223 // case ':POXX#': //N/A Temperature calibration offset, XX is a two-digit signed hex number, in half degree increments. Example 1: :PO02# offset of +1°C Example 2: :POFB# offset of -2.5°
rakware 0:c990fafbe0fc 224 // break; //TODO
rakware 0:c990fafbe0fc 225
rakware 0:c990fafbe0fc 226 default:
rakware 0:c990fafbe0fc 227 break;
rakware 0:c990fafbe0fc 228 }
rakware 0:c990fafbe0fc 229 break;
rakware 0:c990fafbe0fc 230
rakware 0:c990fafbe0fc 231 case ':':
rakware 0:c990fafbe0fc 232 idx=0;
rakware 0:c990fafbe0fc 233 memset(ml_in, 0, 8);
rakware 0:c990fafbe0fc 234 break;
rakware 0:c990fafbe0fc 235
rakware 0:c990fafbe0fc 236 default:
rakware 0:c990fafbe0fc 237 ml_in[idx++] = c;
rakware 0:c990fafbe0fc 238 idx %= 8;
rakware 0:c990fafbe0fc 239 break;
rakware 0:c990fafbe0fc 240 }
rakware 0:c990fafbe0fc 241
rakware 0:c990fafbe0fc 242
rakware 0:c990fafbe0fc 243
rakware 0:c990fafbe0fc 244 }
rakware 8:ccfbd168f077 245 }//while true
rakware 0:c990fafbe0fc 246 }
rakware 0:c990fafbe0fc 247
rakware 0:c990fafbe0fc 248
rakware 0:c990fafbe0fc 249 int main()
rakware 0:c990fafbe0fc 250 {
rakware 4:2235d6d01ca5 251 mp6500();
rakware 0:c990fafbe0fc 252
rakware 8:ccfbd168f077 253 //pc.attach(read_serial, Serial::RxIrq);
rakware 8:ccfbd168f077 254 serial_thread.start(&read_serial);
rakware 4:2235d6d01ca5 255
rakware 8:ccfbd168f077 256 //motor_thread.start(motor);
rakware 8:ccfbd168f077 257 m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250);
rakware 8:ccfbd168f077 258
rakware 4:2235d6d01ca5 259
rakware 4:2235d6d01ca5 260 while(true) {
rakware 8:ccfbd168f077 261 Thread::wait(1);
rakware 4:2235d6d01ca5 262 }
rakware 0:c990fafbe0fc 263
rakware 0:c990fafbe0fc 264 }