
Telescope motorised focuser based on the moonlite protocol, indilib's indi_monlite_focuser compliant. WIP
main.cpp
- Committer:
- rakware
- Date:
- 2018-08-05
- Revision:
- 8:ccfbd168f077
- Parent:
- 7:30dcdf917330
File content as of revision 8:ccfbd168f077:
#include "mbed.h" //uses https://github.com/ARMmbed/mbed-os/ DigitalOut led(LED1); //board led, just for fun Serial pc(USBTX, USBRX); // tx, rx pc control over usb uint16_t gn = 0; //position to move to uint16_t gp = 0; //current position uint16_t temperature = 255; //hardcoded for now //TODO bool move = false; uint16_t step_delay = 256; //minimum motor speed that will get doubled 5 times to result maximum motor speed //eg: for a value of 16 there will be 5 speeds as follows 16*1,16*2,16*4,16*8,16*16 //eg: for a value of 16 there will be 5 speeds as follows 16,32,64,128,256 uint8_t min_motor_pps = 16; //TODO use max pps since it might be more intuitive? char ml_in[256]; uint8_t idx = 0; Thread serial_thread, motor_thread; Ticker m_speed; void led_blink() { while (true) { led = !led; wait(1); } } //motor control with MP6500 https://www.pololu.com/product/2968 //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 // https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures , 1 kHz or greater, I2 set to low //D2,D3,D4,D5,D6,D7,D8,D9 - DIR, STEP, SLP, I2, I1, MS2, MS1, EN DigitalOut dir(D2); DigitalOut step(D3); DigitalOut slp(D4); //pull high to enable operation DigitalOut i2(D5); //set low to enable pwm power control PwmOut i1(D6); //MP6500 power limit control DigitalOut ms2(D7); //D7 and D8 are PC_14 and PC_15 N/C oscillator pins, hence this is full step only //TODO DigitalOut ms1(D8); //set low for FULL or high for HALF, only use MS1 to be moonlite compliant ? DigitalOut en(D9); //pulled low by the motor driver, default enables operation float motor_max_amps = 0.33f; float pw = (motor_max_amps-2.2f)/-2.079f; //https://www.pololu.com/product/2968#lightbox-picture0J8398;main-pictures void mp6500() //TODO enable/disable motor { dir = 0; step = 0; slp = 1; i2 = 0; i1.period(0.001f); //1kHz period i1.write(1.0f); //start with lowest power since we're idle ms2 = 0; ms1 = 1; en = 0; } void m_step() { //while (true) { if(move) { i1.write(pw); //set defined current motor while moving if(gp > gn) { dir = 0; wait_us(1); //led = !led; step = !step; wait_us(1); //mp6500 //led = !led; step = !step; wait_us(1); //https://os.mbed.com/docs/v5.9/mbed-os-api-doxy/mbed__wait__api_8h_source.html use Thread::wait()? //wait((step_delay/1.024)/min_motor_pps/250); gp--; } else if (gp < gn) { dir = 1; wait_us(1); //led = !led; step = !step; wait_us(1); //led = !led; step = !step; wait_us(1); //wait((step_delay/1.024)/min_motor_pps/250); gp++; } else { step = dir = 0; wait_us(1); i1.write(1.0f); //set minimum controller power while holding, keeps motor cool and still provides a nice holding torque, ~120ma move = false; } } //} } //http://indilib.org/media/kunena/attachments/1/HighResSteppermotor107.pdf void read_serial() { while(true){ if(pc.readable()) { char c = pc.getc(); switch (c) { case '#': switch (ml_in[0]) { 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. break; //TODO case 'F': switch (ml_in[1]) { case 'G': //N/A Go to the new position as set by the ":SNYYYY#" command. move = true; //runs motor(); break; case 'Q': //N/A Immediately stop any focus motor movement. move = false; break; default: break; } break; case 'G': switch (ml_in[1]) { case 'B': // Get the backlight value pc.printf("00#"); break; case 'C': //XX# Returns the temperature coefficient where XX is a two-digit signed (2’s complement) hex number. pc.printf("02#"); break; 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 pc.printf("%02X#", 512 / step_delay); //TODO? we sleep for step_delay*step_delay_multiplier microseconds between steps break; case 'H': //00# OR FF# Returns "FF#" if the focus motor is half-stepped otherwise return "00#" //pc.printf("00#"); //TODO pc.printf("%02X#", ms1 * 255); break; case 'I': //00# OR 01# Returns "00#" if the focus motor is not moving, otherwise return "01#" pc.printf("%02X#", move); break; case 'N': //YYYY# Returns the new position previously set by a ":SNYYYY#" command where YYYY is a four-digit unsigned hex number pc.printf("%04X#", gn); //TODO use this to move the motor break; case 'P': //YYYY# Returns the current position where YYYY is a four-digit unsigned hex number. pc.printf("%04X#", gp); //TODO update gp with actual motor data break; case 'T': //YYYY# Returns the current temperature where YYYY is a four-digit signed (2’s complement) hex number. pc.printf("%04X#", temperature * 2); //indi_moonlite_focuser returns the temp/2, dunno why, dont care //pc.printf("0019#"); //should be 25c but is 12.5c in indi_moonlite control panel break; 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. pc.printf("01#"); break; default: break; } break; case 'S': switch(ml_in[1]) { case 'C': //N/A Set the new temperature coefficient where XX is a two-digit, signed (2’s complement) hex number. break; //TODO 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. step_delay = 512 / strtol(ml_in + 2, NULL, 16); m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250); break; case 'F': //N/A Set full-step mode. ms1 = 0; break; case 'H': //N/A Set half-step mode. ms1 = 1; break; case 'N': //N/A Set the new position where YYYY is a four-digit unsigned hex number. gn = strtol(ml_in + 2, NULL, 16); //read ml_in, discard 2 chars, convert to long, set gn break; case 'P': //Set the current position where YYYY is a four-digit unsigned hex number. gp = strtol(ml_in + 2, NULL, 16); break; default: break; } break; case '+': //N/A Activate temperature compensation focusing. break; //TODO case '-': //N/A Disable temperature compensation focusing. break; //TODO case 'P': break; // 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° // break; //TODO default: break; } break; case ':': idx=0; memset(ml_in, 0, 8); break; default: ml_in[idx++] = c; idx %= 8; break; } } }//while true } int main() { mp6500(); //pc.attach(read_serial, Serial::RxIrq); serial_thread.start(&read_serial); //motor_thread.start(motor); m_speed.attach(&m_step, (step_delay/1.024)/min_motor_pps/250); while(true) { Thread::wait(1); } }