Now you can download a copy of these docs so you can use them offline! Download now
Ultrasonic.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "Ultrasonic.h" 00008 00009 #include "Counter.h" 00010 #include "DigitalInput.h" 00011 #include "DigitalOutput.h" 00012 #include "Timer.h" 00013 #include "Utility.h" 00014 #include "WPIErrors.h" 00015 00016 const double Ultrasonic::kPingTime; 00017 const UINT32 Ultrasonic::kPriority; 00018 const double Ultrasonic::kMaxUltrasonicTime; 00019 const double Ultrasonic::kSpeedOfSoundInchesPerSec; 00020 Task Ultrasonic::m_task("UltrasonicChecker", (FUNCPTR)UltrasonicChecker); // task doing the round-robin automatic sensing 00021 Ultrasonic *Ultrasonic::m_firstSensor = NULL; // head of the ultrasonic sensor list 00022 bool Ultrasonic::m_automaticEnabled = false; // automatic round robin mode 00023 SEM_ID Ultrasonic::m_semaphore = 0; 00024 00034 void Ultrasonic::UltrasonicChecker() 00035 { 00036 Ultrasonic *u = NULL; 00037 while (m_automaticEnabled) 00038 { 00039 if (u == NULL) u = m_firstSensor; 00040 if (u == NULL) return; 00041 if (u->IsEnabled()) 00042 u->m_pingChannel->Pulse(kPingTime); // do the ping 00043 u = u->m_nextSensor; 00044 Wait(0.1); // wait for ping to return 00045 } 00046 } 00047 00055 void Ultrasonic::Initialize() 00056 { 00057 bool originalMode = m_automaticEnabled; 00058 if (m_semaphore == 0) m_semaphore = semBCreate(SEM_Q_PRIORITY, SEM_FULL); 00059 SetAutomaticMode(false); // kill task when adding a new sensor 00060 semTake(m_semaphore, WAIT_FOREVER); // link this instance on the list 00061 { 00062 m_nextSensor = m_firstSensor; 00063 m_firstSensor = this; 00064 } 00065 semGive(m_semaphore); 00066 00067 m_counter = new Counter(m_echoChannel); // set up counter for this sensor 00068 m_counter->SetMaxPeriod(1.0); 00069 m_counter->SetSemiPeriodMode(true); 00070 m_counter->Reset(); 00071 m_counter->Start(); 00072 m_enabled = true; // make it available for round robin scheduling 00073 SetAutomaticMode(originalMode); 00074 } 00075 00086 Ultrasonic::Ultrasonic(UINT32 pingChannel, UINT32 echoChannel, DistanceUnit units) 00087 { 00088 m_pingChannel = new DigitalOutput(pingChannel); 00089 m_echoChannel = new DigitalInput(echoChannel); 00090 m_allocatedChannels = true; 00091 m_units = units; 00092 Initialize(); 00093 } 00094 00102 Ultrasonic::Ultrasonic(DigitalOutput *pingChannel, DigitalInput *echoChannel, DistanceUnit units) 00103 { 00104 if (pingChannel == NULL || echoChannel == NULL) 00105 { 00106 wpi_setWPIError(NullParameter); 00107 return; 00108 } 00109 m_allocatedChannels = false; 00110 m_pingChannel = pingChannel; 00111 m_echoChannel = echoChannel; 00112 m_units = units; 00113 Initialize(); 00114 } 00115 00123 Ultrasonic::Ultrasonic(DigitalOutput &pingChannel, DigitalInput &echoChannel, DistanceUnit units) 00124 { 00125 m_allocatedChannels = false; 00126 m_pingChannel = &pingChannel; 00127 m_echoChannel = &echoChannel; 00128 m_units = units; 00129 Initialize(); 00130 } 00131 00144 Ultrasonic::Ultrasonic(UINT8 pingModuleNumber, UINT32 pingChannel, 00145 UINT8 echoModuleNumber, UINT32 echoChannel, DistanceUnit units) 00146 { 00147 m_pingChannel = new DigitalOutput(pingModuleNumber, pingChannel); 00148 m_echoChannel = new DigitalInput(echoModuleNumber, echoChannel); 00149 m_allocatedChannels = true; 00150 m_units = units; 00151 Initialize(); 00152 } 00153 00160 Ultrasonic::~Ultrasonic() 00161 { 00162 bool wasAutomaticMode = m_automaticEnabled; 00163 SetAutomaticMode(false); 00164 if (m_allocatedChannels) 00165 { 00166 delete m_pingChannel; 00167 delete m_echoChannel; 00168 } 00169 wpi_assert(m_firstSensor != NULL); 00170 00171 semTake(m_semaphore, WAIT_FOREVER); 00172 { 00173 if (this == m_firstSensor) 00174 { 00175 m_firstSensor = m_nextSensor; 00176 if (m_firstSensor == NULL) 00177 { 00178 SetAutomaticMode(false); 00179 } 00180 } 00181 else 00182 { 00183 wpi_assert(m_firstSensor->m_nextSensor != NULL); 00184 for (Ultrasonic *s = m_firstSensor; s != NULL; s = s->m_nextSensor) 00185 { 00186 if (this == s->m_nextSensor) 00187 { 00188 s->m_nextSensor = s->m_nextSensor->m_nextSensor; 00189 break; 00190 } 00191 } 00192 } 00193 } 00194 semGive(m_semaphore); 00195 if (m_firstSensor != NULL && wasAutomaticMode) 00196 SetAutomaticMode(true); 00197 } 00198 00208 void Ultrasonic::SetAutomaticMode(bool enabling) 00209 { 00210 if (enabling == m_automaticEnabled) 00211 return; // ignore the case of no change 00212 00213 m_automaticEnabled = enabling; 00214 if (enabling) 00215 { 00216 // enabling automatic mode. 00217 // Clear all the counters so no data is valid 00218 for (Ultrasonic *u = m_firstSensor; u != NULL; u = u->m_nextSensor) 00219 { 00220 u->m_counter->Reset(); 00221 } 00222 // Start round robin task 00223 wpi_assert(m_task.Verify() == false); // should be false since was previously disabled 00224 m_task.Start(); 00225 } 00226 else 00227 { 00228 // disabling automatic mode. Wait for background task to stop running. 00229 while (m_task.Verify()) 00230 Wait(0.15); // just a little longer than the ping time for round-robin to stop 00231 00232 // clear all the counters (data now invalid) since automatic mode is stopped 00233 for (Ultrasonic *u = m_firstSensor; u != NULL; u = u->m_nextSensor) 00234 { 00235 u->m_counter->Reset(); 00236 } 00237 m_task.Stop(); 00238 } 00239 } 00240 00247 void Ultrasonic::Ping() 00248 { 00249 // TODO: Either assert or disable, not both. 00250 wpi_assert(!m_automaticEnabled); 00251 SetAutomaticMode(false); // turn off automatic round robin if pinging single sensor 00252 m_counter->Reset(); // reset the counter to zero (invalid data now) 00253 m_pingChannel->Pulse(kPingTime); // do the ping to start getting a single range 00254 } 00255 00261 bool Ultrasonic::IsRangeValid() 00262 { 00263 return m_counter->Get() > 1; 00264 } 00265 00271 double Ultrasonic::GetRangeInches() 00272 { 00273 if (IsRangeValid()) 00274 return m_counter->GetPeriod() * kSpeedOfSoundInchesPerSec / 2.0; 00275 else 00276 return 0; 00277 } 00278 00284 double Ultrasonic::GetRangeMM() 00285 { 00286 return GetRangeInches() * 25.4; 00287 } 00288 00294 double Ultrasonic::PIDGet() 00295 { 00296 switch(m_units) 00297 { 00298 case Ultrasonic::kInches: 00299 return GetRangeInches(); 00300 case Ultrasonic::kMilliMeters: 00301 return GetRangeMM(); 00302 default: 00303 return 0.0; 00304 } 00305 } 00306 00312 void Ultrasonic::SetDistanceUnits(DistanceUnit units) 00313 { 00314 m_units = units; 00315 } 00316 00322 Ultrasonic::DistanceUnit Ultrasonic::GetDistanceUnits() 00323 { 00324 return m_units; 00325 }
Generated on Thu Jan 12 2012 22:35:24 for WPILibC++ by
1.7.1