#include "Arduino.h" #include "RoboClaw.h" #define MAXRETRY 2 #define SetDWORDval(arg) (uint8_t)(((uint32_t)arg)>>24),(uint8_t)(((uint32_t)arg)>>16),(uint8_t)(((uint32_t)arg)>>8),(uint8_t)arg #define SetWORDval(arg) (uint8_t)(((uint16_t)arg)>>8),(uint8_t)arg // // Constructor // RoboClaw::RoboClaw(HardwareSerial *serial, uint32_t tout) { timeout = tout; hserial = serial; #ifdef __AVR__ sserial = 0; #endif } #ifdef __AVR__ RoboClaw::RoboClaw(SoftwareSerial *serial, uint32_t tout) { timeout = tout; sserial = serial; hserial = 0; } #endif // // Destructor // RoboClaw::~RoboClaw() { } void RoboClaw::begin(long speed) { if(hserial){ hserial->begin(speed); } #ifdef __AVR__ else{ sserial->begin(speed); } #endif } bool RoboClaw::listen() { #ifdef __AVR__ if(sserial){ return sserial->listen(); } #endif return false; } bool RoboClaw::isListening() { #ifdef __AVR__ if(sserial) return sserial->isListening(); #endif return false; } bool RoboClaw::overflow() { #ifdef __AVR__ if(sserial) return sserial->overflow(); #endif return false; } int RoboClaw::peek() { if(hserial) return hserial->peek(); #ifdef __AVR__ else return sserial->peek(); #endif } size_t RoboClaw::write(uint8_t byte) { if(hserial) return hserial->write(byte); #ifdef __AVR__ else return sserial->write(byte); #endif } int RoboClaw::read() { if(hserial) return hserial->read(); #ifdef __AVR__ else return sserial->read(); #endif } int RoboClaw::available() { if(hserial) return hserial->available(); #ifdef __AVR__ else return sserial->available(); #endif } void RoboClaw::flush() { if(hserial) hserial->flush(); } int RoboClaw::read(uint32_t timeout) { if(hserial){ uint32_t start = micros(); // Empty buffer? while(!hserial->available()){ if((micros()-start)>=timeout) return -1; } return hserial->read(); } #ifdef __AVR__ else{ if(sserial->isListening()){ uint32_t start = micros(); // Empty buffer? while(!sserial->available()){ if((micros()-start)>=timeout) return -1; } return sserial->read(); } } #endif } void RoboClaw::clear() { if(hserial){ while(hserial->available()) hserial->read(); } #ifdef __AVR__ else{ while(sserial->available()) sserial->read(); } #endif } void RoboClaw::crc_clear() { crc = 0; } void RoboClaw::crc_update (uint8_t data) { int i; crc = crc ^ ((uint16_t)data << 8); for (i=0; i<8; i++) { if (crc & 0x8000) crc = (crc << 1) ^ 0x1021; else crc <<= 1; } } uint16_t RoboClaw::crc_get() { return crc; } bool RoboClaw::write_n(uint8_t cnt, ... ) { uint8_t trys=MAXRETRY; do{ crc_clear(); //send data with crc va_list marker; va_start( marker, cnt ); /* Initialize variable arguments. */ for(uint8_t index=0;index>8); write(crc); if(read(timeout)==0xFF) return true; }while(trys--); return false; } bool RoboClaw::read_n(uint8_t cnt,uint8_t address,uint8_t cmd,...) { uint32_t value=0; uint8_t trys=MAXRETRY; int16_t data; do{ flush(); data=0; crc_clear(); write(address); crc_update(address); write(cmd); crc_update(cmd); //send data with crc va_list marker; va_start( marker, cmd ); /* Initialize variable arguments. */ for(uint8_t index=0;index>8; depth2 = value; } return valid; } bool RoboClaw::ReadPWMs(uint8_t address, int16_t &pwm1, int16_t &pwm2){ bool valid; uint32_t value = Read4(address,GETPWMS,&valid); if(valid){ pwm1 = value>>16; pwm2 = value&0xFFFF; } return valid; } bool RoboClaw::ReadCurrents(uint8_t address, int16_t ¤t1, int16_t ¤t2){ bool valid; uint32_t value = Read4(address,GETCURRENTS,&valid); if(valid){ current1 = value>>16; current2 = value&0xFFFF; } return valid; } bool RoboClaw::SpeedAccelM1M2_2(uint8_t address, uint32_t accel1, uint32_t speed1, uint32_t accel2, uint32_t speed2){ return write_n(18,address,MIXEDSPEED2ACCEL,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(accel2),SetDWORDval(speed2)); } bool RoboClaw::SpeedAccelDistanceM1M2_2(uint8_t address, uint32_t accel1, uint32_t speed1, uint32_t distance1, uint32_t accel2, uint32_t speed2, uint32_t distance2, uint8_t flag){ return write_n(27,address,MIXEDSPEED2ACCELDIST,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(distance1),SetDWORDval(accel2),SetDWORDval(speed2),SetDWORDval(distance2),flag); } bool RoboClaw::DutyAccelM1(uint8_t address, uint16_t duty, uint32_t accel){ return write_n(8,address,M1DUTYACCEL,SetWORDval(duty),SetDWORDval(accel)); } bool RoboClaw::DutyAccelM2(uint8_t address, uint16_t duty, uint32_t accel){ return write_n(8,address,M2DUTYACCEL,SetWORDval(duty),SetDWORDval(accel)); } bool RoboClaw::DutyAccelM1M2(uint8_t address, uint16_t duty1, uint32_t accel1, uint16_t duty2, uint32_t accel2){ return write_n(14,address,MIXEDDUTYACCEL,SetWORDval(duty1),SetDWORDval(accel1),SetWORDval(duty2),SetDWORDval(accel2)); } bool RoboClaw::ReadM1VelocityPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &qpps){ uint32_t Kp,Ki,Kd; bool valid = read_n(4,address,READM1PID,&Kp,&Ki,&Kd,&qpps); Kp_fp = ((float)Kp)/65536; Ki_fp = ((float)Ki)/65536; Kd_fp = ((float)Kd)/65536; return valid; } bool RoboClaw::ReadM2VelocityPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &qpps){ uint32_t Kp,Ki,Kd; bool valid = read_n(4,address,READM2PID,&Kp,&Ki,&Kd,&qpps); Kp_fp = ((float)Kp)/65536; Ki_fp = ((float)Ki)/65536; Kd_fp = ((float)Kd)/65536; return valid; } bool RoboClaw::SetMainVoltages(uint8_t address,uint16_t min,uint16_t max){ return write_n(6,address,SETMAINVOLTAGES,SetWORDval(min),SetWORDval(max)); } bool RoboClaw::SetLogicVoltages(uint8_t address,uint16_t min,uint16_t max){ return write_n(6,address,SETLOGICVOLTAGES,SetWORDval(min),SetWORDval(max)); } bool RoboClaw::ReadMinMaxMainVoltages(uint8_t address,uint16_t &min,uint16_t &max){ bool valid; uint32_t value = Read4(address,GETMINMAXMAINVOLTAGES,&valid); if(valid){ min = value>>16; max = value&0xFFFF; } return valid; } bool RoboClaw::ReadMinMaxLogicVoltages(uint8_t address,uint16_t &min,uint16_t &max){ bool valid; uint32_t value = Read4(address,GETMINMAXLOGICVOLTAGES,&valid); if(valid){ min = value>>16; max = value&0xFFFF; } return valid; } bool RoboClaw::SetM1PositionPID(uint8_t address,float kp_fp,float ki_fp,float kd_fp,uint32_t kiMax,uint32_t deadzone,uint32_t min,uint32_t max){ uint32_t kp=kp_fp*1024; uint32_t ki=ki_fp*1024; uint32_t kd=kd_fp*1024; return write_n(30,address,SETM1POSPID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(kiMax),SetDWORDval(deadzone),SetDWORDval(min),SetDWORDval(max)); } bool RoboClaw::SetM2PositionPID(uint8_t address,float kp_fp,float ki_fp,float kd_fp,uint32_t kiMax,uint32_t deadzone,uint32_t min,uint32_t max){ uint32_t kp=kp_fp*1024; uint32_t ki=ki_fp*1024; uint32_t kd=kd_fp*1024; return write_n(30,address,SETM2POSPID,SetDWORDval(kd),SetDWORDval(kp),SetDWORDval(ki),SetDWORDval(kiMax),SetDWORDval(deadzone),SetDWORDval(min),SetDWORDval(max)); } bool RoboClaw::ReadM1PositionPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &KiMax,uint32_t &DeadZone,uint32_t &Min,uint32_t &Max){ uint32_t Kp,Ki,Kd; bool valid = read_n(7,address,READM1POSPID,&Kp,&Ki,&Kd,&KiMax,&DeadZone,&Min,&Max); Kp_fp = ((float)Kp)/1024; Ki_fp = ((float)Ki)/1024; Kd_fp = ((float)Kd)/1024; return valid; } bool RoboClaw::ReadM2PositionPID(uint8_t address,float &Kp_fp,float &Ki_fp,float &Kd_fp,uint32_t &KiMax,uint32_t &DeadZone,uint32_t &Min,uint32_t &Max){ uint32_t Kp,Ki,Kd; bool valid = read_n(7,address,READM2POSPID,&Kp,&Ki,&Kd,&KiMax,&DeadZone,&Min,&Max); Kp_fp = ((float)Kp)/1024; Ki_fp = ((float)Ki)/1024; Kd_fp = ((float)Kd)/1024; return valid; } bool RoboClaw::SpeedAccelDeccelPositionM1(uint8_t address,uint32_t accel,uint32_t speed,uint32_t deccel,uint32_t position,uint8_t flag){ return write_n(19,address,M1SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag); } bool RoboClaw::SpeedAccelDeccelPositionM2(uint8_t address,uint32_t accel,uint32_t speed,uint32_t deccel,uint32_t position,uint8_t flag){ return write_n(19,address,M2SPEEDACCELDECCELPOS,SetDWORDval(accel),SetDWORDval(speed),SetDWORDval(deccel),SetDWORDval(position),flag); } bool RoboClaw::SpeedAccelDeccelPositionM1M2(uint8_t address,uint32_t accel1,uint32_t speed1,uint32_t deccel1,uint32_t position1,uint32_t accel2,uint32_t speed2,uint32_t deccel2,uint32_t position2,uint8_t flag){ return write_n(35,address,MIXEDSPEEDACCELDECCELPOS,SetDWORDval(accel1),SetDWORDval(speed1),SetDWORDval(deccel1),SetDWORDval(position1),SetDWORDval(accel2),SetDWORDval(speed2),SetDWORDval(deccel2),SetDWORDval(position2),flag); } bool RoboClaw::SetM1DefaultAccel(uint8_t address, uint32_t accel){ return write_n(6,address,SETM1DEFAULTACCEL,SetDWORDval(accel)); } bool RoboClaw::SetM2DefaultAccel(uint8_t address, uint32_t accel){ return write_n(6,address,SETM2DEFAULTACCEL,SetDWORDval(accel)); } bool RoboClaw::SetPinFunctions(uint8_t address, uint8_t S3mode, uint8_t S4mode, uint8_t S5mode){ return write_n(5,address,SETPINFUNCTIONS,S3mode,S4mode,S5mode); } bool RoboClaw::GetPinFunctions(uint8_t address, uint8_t &S3mode, uint8_t &S4mode, uint8_t &S5mode){ uint8_t crc; bool valid = false; uint8_t val1,val2,val3; uint8_t trys=MAXRETRY; int16_t data; do{ flush(); crc_clear(); write(address); crc_update(address); write(GETPINFUNCTIONS); crc_update(GETPINFUNCTIONS); data = read(timeout); crc_update(data); val1=data; if(data!=-1){ data = read(timeout); crc_update(data); val2=data; } if(data!=-1){ data = read(timeout); crc_update(data); val3=data; } if(data!=-1){ uint16_t ccrc; data = read(timeout); if(data!=-1){ ccrc = data << 8; data = read(timeout); if(data!=-1){ ccrc |= data; if(crc_get()==ccrc){ S3mode = val1; S4mode = val2; S5mode = val3; return true; } } } } }while(trys--); return false; } bool RoboClaw::SetDeadBand(uint8_t address, uint8_t Min, uint8_t Max){ return write_n(4,address,SETDEADBAND,Min,Max); } bool RoboClaw::GetDeadBand(uint8_t address, uint8_t &Min, uint8_t &Max){ bool valid; uint16_t value = Read2(address,GETDEADBAND,&valid); if(valid){ Min = value>>8; Max = value; } return valid; } bool RoboClaw::ReadEncoders(uint8_t address,uint32_t &enc1,uint32_t &enc2){ bool valid = read_n(2,address,GETENCODERS,&enc1,&enc2); return valid; } bool RoboClaw::ReadISpeeds(uint8_t address,uint32_t &ispeed1,uint32_t &ispeed2){ bool valid = read_n(2,address,GETISPEEDS,&ispeed1,&ispeed2); return valid; } bool RoboClaw::RestoreDefaults(uint8_t address){ return write_n(2,address,RESTOREDEFAULTS); } bool RoboClaw::ReadTemp(uint8_t address, uint16_t &temp){ bool valid; temp = Read2(address,GETTEMP,&valid); return valid; } bool RoboClaw::ReadTemp2(uint8_t address, uint16_t &temp){ bool valid; temp = Read2(address,GETTEMP2,&valid); return valid; } uint16_t RoboClaw::ReadError(uint8_t address,bool *valid){ return Read2(address,GETERROR,valid); } bool RoboClaw::ReadEncoderModes(uint8_t address, uint8_t &M1mode, uint8_t &M2mode){ bool valid; uint16_t value = Read2(address,GETENCODERMODE,&valid); if(valid){ M1mode = value>>8; M2mode = value; } return valid; } bool RoboClaw::SetM1EncoderMode(uint8_t address,uint8_t mode){ return write_n(3,address,SETM1ENCODERMODE,mode); } bool RoboClaw::SetM2EncoderMode(uint8_t address,uint8_t mode){ return write_n(3,address,SETM2ENCODERMODE,mode); } bool RoboClaw::WriteNVM(uint8_t address){ return write_n(6,address,WRITENVM, SetDWORDval(0xE22EAB7A) ); } bool RoboClaw::ReadNVM(uint8_t address){ return write_n(2,address,READNVM); } bool RoboClaw::SetConfig(uint8_t address, uint16_t config){ return write_n(4,address,SETCONFIG,SetWORDval(config)); } bool RoboClaw::GetConfig(uint8_t address, uint16_t &config){ bool valid; uint16_t value = Read2(address,GETCONFIG,&valid); if(valid){ config = value; } return valid; } bool RoboClaw::SetM1MaxCurrent(uint8_t address,uint32_t max){ return write_n(10,address,SETM1MAXCURRENT,SetDWORDval(max),SetDWORDval(0)); } bool RoboClaw::SetM2MaxCurrent(uint8_t address,uint32_t max){ return write_n(10,address,SETM2MAXCURRENT,SetDWORDval(max),SetDWORDval(0)); } bool RoboClaw::ReadM1MaxCurrent(uint8_t address,uint32_t &max){ uint32_t tmax,dummy; bool valid = read_n(2,address,GETM1MAXCURRENT,&tmax,&dummy); if(valid) max = tmax; return valid; } bool RoboClaw::ReadM2MaxCurrent(uint8_t address,uint32_t &max){ uint32_t tmax,dummy; bool valid = read_n(2,address,GETM2MAXCURRENT,&tmax,&dummy); if(valid) max = tmax; return valid; } bool RoboClaw::SetPWMMode(uint8_t address, uint8_t mode){ return write_n(3,address,SETPWMMODE,mode); } bool RoboClaw::GetPWMMode(uint8_t address, uint8_t &mode){ bool valid; uint8_t value = Read1(address,GETPWMMODE,&valid); if(valid){ mode = value; } return valid; }