// %flair:license{ // This file is part of the Flair framework distributed under the // CECILL-C License, Version 1.0. // %flair:license} // created: 2013/04/29 // filename: BlCtrlV2_x4_speed.cpp // // author: Guillaume Sanahuja // Copyright Heudiasyc UMR UTC/CNRS 7253 // // version: $Id: $ // // purpose: objet integrant les moteurs i2c, controle en vitesse // // /*********************************************************************/ #include "BlCtrlV2_x4_speed.h" #include "I2cPort.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define TAU_US 1000 using std::string; using namespace flair::core; using namespace flair::gui; namespace flair { namespace actuator { BlCtrlV2_x4_speed::BlCtrlV2_x4_speed(string name,I2cPort *i2cport, uint8_t base_address, uint8_t priority) : Thread(getFrameworkManager(), name, priority), IODevice(getFrameworkManager(), name) { this->i2cport = i2cport; slave_address = base_address; tested_motor = -1; enabled = false; int_av_g = 0; int_av_d = 0; int_ar_g = 0; int_ar_d = 0; // flight time FILE *file; file = fopen("/etc/flight_time", "r"); if (file == NULL) { Printf("fichier d'info de vol vide\n"); time_sec = 0; } else { char ligne[32]; fgets(ligne, 32, file); time_sec = atoi(ligne); Printf("temps de vol total: %is = %imin = %ih\n", time_sec, time_sec / 60, time_sec / 3600); fclose(file); } // station sol main_tab = new Tab(getFrameworkManager()->GetTabWidget(), name); tab = new TabWidget(main_tab->NewRow(), name); Tab *sensor_tab = new Tab(tab, "Reglages"); reglages_groupbox = new GroupBox(sensor_tab->NewRow(), name); poles = new SpinBox(reglages_groupbox->NewRow(), "nb poles", 0, 255, 1); kp = new DoubleSpinBox(reglages_groupbox->LastRowLastCol(), "kp", 0., 255, 0.001, 4); ki = new DoubleSpinBox(reglages_groupbox->LastRowLastCol(), "ki", 0., 255, 0.001, 4); min = new SpinBox(reglages_groupbox->NewRow(), "min pwm", 0., 2048, 1); max = new SpinBox(reglages_groupbox->LastRowLastCol(), "max pwm", 0., 2048, 1); test = new SpinBox(reglages_groupbox->LastRowLastCol(), "test value", 0., 2048, 1); start_value = new SpinBox(reglages_groupbox->NewRow(), "valeur demarrage", 0, 10000, 10); trim = new DoubleSpinBox(reglages_groupbox->LastRowLastCol(), "pas decollage", 0, 1000, .1); av_g = new ComboBox(reglages_groupbox->NewRow(), "avant gauche"); av_g->AddItem("1"); av_g->AddItem("2"); av_g->AddItem("3"); av_g->AddItem("4"); button_avg = new PushButton(reglages_groupbox->LastRowLastCol(), "test avg"); av_d = new ComboBox(reglages_groupbox->LastRowLastCol(), "avant droite:"); av_d->AddItem("1"); av_d->AddItem("2"); av_d->AddItem("3"); av_d->AddItem("4"); button_avd = new PushButton(reglages_groupbox->LastRowLastCol(), "test avd"); ar_g = new ComboBox(reglages_groupbox->NewRow(), "arriere gauche:"); ar_g->AddItem("1"); ar_g->AddItem("2"); ar_g->AddItem("3"); ar_g->AddItem("4"); button_arg = new PushButton(reglages_groupbox->LastRowLastCol(), "test arg"); ar_d = new ComboBox(reglages_groupbox->LastRowLastCol(), "arriere droite:"); ar_d->AddItem("1"); ar_d->AddItem("2"); ar_d->AddItem("3"); ar_d->AddItem("4"); button_ard = new PushButton(reglages_groupbox->LastRowLastCol(), "test ard"); pas = new ComboBox(reglages_groupbox->NewRow(), "pas helice avant gauche:"); pas->AddItem("normal"); pas->AddItem("inverse"); input = new cvmatrix((IODevice *)this, 8, 1, floatType); cvmatrix_descriptor *desc = new cvmatrix_descriptor(4, 2); desc->SetElementName(0, 0, "avant gauche"); desc->SetElementName(1, 0, "arriere droite"); desc->SetElementName(2, 0, "avant droite"); desc->SetElementName(3, 0, "arriere gauche"); desc->SetElementName(0, 1, "cons avant gauche"); desc->SetElementName(1, 1, "cons arriere droite"); desc->SetElementName(2, 1, "cons avant droite"); desc->SetElementName(3, 1, "cons arriere gauche"); output = new cvmatrix((IODevice *)this, desc, floatType); /* //le 3ieme lu est la tension batteire if(i2c_mutex!=NULL) i2c_mutex->GetMutex(); uint16_t pwm_moteur; pwm_moteur=0; ssize_t read; uint8_t rx[8]; SetSlave(slave_address); for(int j=0;j<10;j++) { WriteValue(pwm_moteur); read = rt_dev_read(i2c_fd, rx, sizeof(rx)); if(read<0) { rt_printf("BlCtrlV2_x4_speed::BlCtrlV2_x4_speed: %s, erreur rt_dev_read (%s)\n",IODevice::ObjectName().c_str(),strerror(-read)); } else if (read != sizeof(rx)) { rt_printf("BlCtrlV2_x4_speed::BlCtrlV2_x4_speed: %s, erreur rt_dev_read %i/2\n",IODevice::ObjectName().c_str(),read); } for(int i=0;iReleaseMutex();*/ } BlCtrlV2_x4_speed::~BlCtrlV2_x4_speed(void) { SafeStop(); Join(); delete main_tab; } void BlCtrlV2_x4_speed::UseDefaultPlot(void) { Tab *plot_tab = new Tab(tab, "Mesures"); DataPlot1D *av_g_plot = new DataPlot1D(plot_tab->NewRow(), "avg", 0, 10000); av_g_plot->AddCurve(output->Element(0, 0)); av_g_plot->AddCurve(output->Element(0, 1), DataPlot::Blue); DataPlot1D *av_d_plot = new DataPlot1D(plot_tab->LastRowLastCol(), "avd", 0, 10000); av_d_plot->AddCurve(output->Element(2, 0)); av_d_plot->AddCurve(output->Element(2, 1), DataPlot::Blue); DataPlot1D *ar_g_plot = new DataPlot1D(plot_tab->NewRow(), "arg", 0, 10000); ar_g_plot->AddCurve(output->Element(3, 0)); ar_g_plot->AddCurve(output->Element(3, 1), DataPlot::Blue); DataPlot1D *ar_d_plot = new DataPlot1D(plot_tab->LastRowLastCol(), "ard", 0, 10000); ar_d_plot->AddCurve(output->Element(1, 0)); ar_d_plot->AddCurve(output->Element(1, 1), DataPlot::Blue); } float BlCtrlV2_x4_speed::TrimValue(void) { return (float)trim->Value(); } int BlCtrlV2_x4_speed::StartValue(void) { return start_value->Value(); } void BlCtrlV2_x4_speed::Run(void) { WarnUponSwitches(true); SetPeriodUS(TAU_US); while (!ToBeStopped()) { WaitPeriod(); Update(); } WarnUponSwitches(false); } void BlCtrlV2_x4_speed::Update(void) { float u_roll, u_pitch, u_yaw, u_gaz; float trim_roll, trim_pitch, trim_yaw; float pwm[4]; uint16_t pwm_moteur[4]; // on prend une fois pour toute le mutex et on fait des accès directs input->GetMutex(); u_roll = input->ValueNoMutex(0, 0); u_pitch = input->ValueNoMutex(1, 0); u_yaw = input->ValueNoMutex(2, 0); u_gaz = input->ValueNoMutex(3, 0) + input->ValueNoMutex(7, 0) * input->ValueNoMutex(7, 0); // ugaz+trim*trim trim_roll = input->ValueNoMutex(4, 0); trim_pitch = input->ValueNoMutex(5, 0); trim_yaw = input->ValueNoMutex(6, 0); input->ReleaseMutex(); if (pas->CurrentIndex() == 1) { trim_yaw = -trim_yaw; u_yaw = -u_yaw; } // rt_printf("%f %f %f %f\n",u_roll,u_pitch,u_yaw,u_gaz); // if(u_gaz!=0) rt_printf("gaz: %f\n",u_gaz); // avant gauche if (u_gaz + u_pitch + u_roll + u_yaw > 0) { pwm[0] = trim_pitch + trim_roll + trim_yaw + sqrtf(u_gaz + u_pitch + u_roll + u_yaw); } else { pwm[0] = trim_pitch + trim_roll + trim_yaw; } // arriere gauche if (u_gaz - u_pitch + u_roll - u_yaw > 0) { pwm[3] = -trim_pitch + trim_roll - trim_yaw + sqrtf(u_gaz - u_pitch + u_roll - u_yaw); } else { pwm[3] = -trim_pitch + trim_roll - trim_yaw; } // arriere droit if (u_gaz - u_pitch - u_roll + u_yaw > 0) { pwm[1] = -trim_pitch - trim_roll + trim_yaw + sqrtf(u_gaz - u_pitch - u_roll + u_yaw); } else { pwm[1] = -trim_pitch - trim_roll + trim_yaw; } // avant droit if (u_gaz + u_pitch - u_roll - u_yaw > 0) { pwm[2] = trim_pitch - trim_roll - trim_yaw + sqrtf(u_gaz + u_pitch - u_roll - u_yaw); } else { pwm[2] = trim_pitch - trim_roll - trim_yaw; } int_av_g += ki->Value() * (pwm[0] - speed_av_g); pwm[0] = kp->Value() * (pwm[0] - speed_av_g) + int_av_g; int_ar_g += ki->Value() * (pwm[3] - speed_ar_g); pwm[3] = kp->Value() * (pwm[3] - speed_ar_g) + int_ar_g; int_ar_d += ki->Value() * (pwm[1] - speed_ar_d); pwm[1] = kp->Value() * (pwm[1] - speed_ar_d) + int_ar_d; int_av_d += ki->Value() * (pwm[2] - speed_av_d); pwm[2] = kp->Value() * (pwm[2] - speed_av_d) + int_av_d; // rt_printf("%f\n",pwm[0]); for (int i = 0; i < 4; i++) pwm_moteur[i] = SatPWM(pwm[i], min->Value(), max->Value()); if (button_avg->Clicked() == true) { tested_motor = 0; StartTest(); } if (button_avd->Clicked() == true) { tested_motor = 2; StartTest(); } if (button_arg->Clicked() == true) { tested_motor = 3; StartTest(); } if (button_ard->Clicked() == true) { tested_motor = 1; StartTest(); } if (tested_motor != -1) { for (int i = 0; i < 4; i++) { pwm_moteur[i] = 0; } pwm_moteur[tested_motor] = (uint16_t)test->Value(); if (GetTime() > (start_time + 2 * 1000000000)) StopTest(); } i2cport->GetMutex(); if (enabled == true) { i2cport->SetSlave(slave_address + av_g->CurrentIndex()); WriteValue(pwm_moteur[0]); i2cport->SetSlave(slave_address + av_d->CurrentIndex()); WriteValue(pwm_moteur[2]); i2cport->SetSlave(slave_address + ar_g->CurrentIndex()); WriteValue(pwm_moteur[3]); i2cport->SetSlave(slave_address + ar_d->CurrentIndex()); WriteValue(pwm_moteur[1]); } else { for (int i = 0; i < 4; i++) { i2cport->SetSlave(slave_address + i); WriteValue(0); } int_av_g = 0; int_av_d = 0; int_ar_g = 0; int_ar_d = 0; } i2cport->SetSlave(slave_address + av_g->CurrentIndex()); speed_av_g = GetSpeed(); i2cport->SetSlave(slave_address + av_d->CurrentIndex()); speed_av_d = GetSpeed(); i2cport->SetSlave(slave_address + ar_g->CurrentIndex()); speed_ar_g = GetSpeed(); i2cport->SetSlave(slave_address + ar_d->CurrentIndex()); speed_ar_d = GetSpeed(); i2cport->ReleaseMutex(); // on prend une fois pour toute le mutex et on fait des accès directs output->GetMutex(); output->SetValueNoMutex(0, 0, speed_av_g); output->SetValueNoMutex(1, 0, speed_ar_d); output->SetValueNoMutex(2, 0, speed_av_d); output->SetValueNoMutex(3, 0, speed_ar_g); // rt_printf("%i %i %i // %i\n",pwm_moteur[0],pwm_moteur[1],pwm_moteur[2],pwm_moteur[3]); output->ReleaseMutex(); output->SetDataTime(GetTime()); ProcessUpdate(output); } void BlCtrlV2_x4_speed::StartTest(void) { start_time = GetTime(); SetEnabled(true); } void BlCtrlV2_x4_speed::StopTest(void) { SetEnabled(false); tested_motor = -1; } uint16_t BlCtrlV2_x4_speed::SatPWM(float vel_cons, uint16_t min, uint16_t max) { uint16_t sat_value = (uint16_t)vel_cons; if (vel_cons > ((float)sat_value + 0.5)) sat_value++; if (vel_cons < (float)min) sat_value = min; if (vel_cons > (float)max) sat_value = max; return sat_value; } void BlCtrlV2_x4_speed::LockUserInterface(void) { reglages_groupbox->setEnabled(false); } void BlCtrlV2_x4_speed::UnlockUserInterface(void) { reglages_groupbox->setEnabled(true); } void BlCtrlV2_x4_speed::SetEnabled(bool status) { enabled = status; if (enabled == true) { LockUserInterface(); flight_start_time = GetTime(); } else { UnlockUserInterface(); Time now = GetTime(); int t_sec; FILE *file; char ligne[32]; t_sec = (now - flight_start_time) / 1000000000; time_sec += t_sec; Printf("temps de vol: %is = %imin\n", t_sec, t_sec / 60); Printf("temps de vol total: %is = %imin = %ih\n", time_sec, time_sec / 60, time_sec / 3600); file = fopen("/etc/flight_time", "w"); if (file == NULL) { Thread::Err("Erreur a l'ouverture du fichier d'info vol\n"); } else { sprintf(ligne, "%i", time_sec); fputs(ligne, file); fclose(file); } } } void BlCtrlV2_x4_speed::SetUroll(float value) { input->SetValue(0, 0, value); } void BlCtrlV2_x4_speed::SetUpitch(float value) { input->SetValue(1, 0, value); } void BlCtrlV2_x4_speed::SetUyaw(float value) { input->SetValue(2, 0, value); } void BlCtrlV2_x4_speed::SetUgaz(float value) { input->SetValue(3, 0, value); } void BlCtrlV2_x4_speed::SetRollTrim(float value) { input->SetValue(4, 0, value); } void BlCtrlV2_x4_speed::SetPitchTrim(float value) { input->SetValue(5, 0, value); } void BlCtrlV2_x4_speed::SetYawTrim(float value) { input->SetValue(6, 0, value); } void BlCtrlV2_x4_speed::SetGazTrim(float value) { input->SetValue(7, 0, value); } void BlCtrlV2_x4_speed::WriteValue(uint16_t value) { unsigned char tx[2]; ssize_t written; tx[0] = (unsigned char)(value >> 3); // msb tx[1] = 16 + 8 + (value & 0x07); // 16+8 pour recuperer la vitesse written = i2cport->Write(tx, 2); if (written < 0) { Thread::Err("erreur rt_dev_write (%s)\n", strerror(-written)); } else if (written != 2) { Thread::Err("erreur rt_dev_write %i/2\n", written); } } float BlCtrlV2_x4_speed::GetSpeed(void) { ssize_t read; uint8_t value; read = i2cport->Read(&value, 1); if (read < 0) { Thread::Err("erreur rt_dev_read (%s)\n", strerror(-read)); } else if (read != 1) { Thread::Err("erreur rt_dev_read %i/2\n", read); } return value * 780. / poles->Value(); } } // end namespace actuator } // end namespace framewor