Main Page · Modules · All Classes · Class Hierarchy
MAWalkMaster.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MAWalkMaster.hpp"
23 
24 #include "core/MARandomness.hpp"
25 #include "types/MABodyMotion.hpp"
26 #include "types/MAComplexIndicators.hpp"
27 #include "types/MAGoals.hpp"
28 #include "types/MARobotState.hpp"
29 #include "types/MATorso.hpp"
30 #include "types/MATypeRanges.hpp"
31 #include "controllers/MAHeadController.hpp"
32 #include "controllers/MALegController.hpp"
33 #include "ml/MAClassifierModels.hpp"
34 #include "ml/MADataCollector.hpp"
35 #include "ml/MASurfaceAnalyzer.hpp"
36 #include "MAAvoidObstacleMaster.hpp"
37 #include "MABehaviorManager.hpp"
38 #include "MABodyAdjustStandingPosture.hpp"
39 #include "MABodyStateMaster.hpp"
40 #include "MABodyStroked.hpp"
41 #include "MAHeadLookAround.hpp"
42 #include "MAHeadLookAroundMaster.hpp"
43 #include "MARecognizeFloorSurface.hpp"
44 #include "MAWalkFreefall.hpp"
45 #include "MAWalkInitialPosition.hpp"
46 #include "MAWaitFloorFeedback.hpp"
47 
48 #include <MCDataContainer.hpp>
49 
50 MAWalkMaster::MAWalkMaster() : MABehavior(MCGetClassName(this)),
51  MARobotStateUpdater(MA::UpdateComplexIndicators), WalkStartTimestamp(-1),
52  RecognizedSurface((int)MA::UnknownFloor), RecognizedCurrentSurface((int)MA::UnknownFloor),
53  SurfaceRecognitionTimer(new MCTimer(MC::SimpleExpiration))
54 {
55  // The default walk period is 2400 and the dog is the same posture after every ~2030 msecs
56  SurfaceRecognitionTimer->SetDuration(2410);
57  RegisterUpdater(*this);
58  // Avoid to activate the body state change behavior
59  DesiredConnections[MCGetClassName<MABodyStateMaster>()] = -1.0;
60  DesiredConnections[MCGetClassName<MABodyStroked>()] = -1.0;
61  DesiredConnections[MCGetClassName<MAHeadLookAroundMaster>()] = -1.0;
62 }
63 
64 
65 void MAWalkMaster::StartWalk()
66 {
68  {
69  WalkStartTimestamp = GetElapsedActivatedStateTime();
70  // Set a random walk duration if it has not been set yet (exploration mode)
71  if (MA::RobotState->Goals->DesiredForwardWalkDuration < 2000 &&
72  MA::RobotState->Goals->DesiredBackwardWalkDuration < 2000)
73  {
74  // Set a random walk duration
75  // Note: The first second is used to go into initial walk posture and ~10 seconds is
76  // needed to get the underlying surface recognized.
77  MA_RANDOM_POINT_1(NewDuration, 11000, 60000);
78 
79  MA::RobotState->Goals->DesiredForwardWalkDuration = NewDuration;
80  MA::RobotState->Goals->DesiredBackwardWalkDuration = 0;
81  }
82  }
83 }
84 
85 
87 {
89 }
90 
91 
93 {
95  // Stop look around
97 }
98 
99 
101 {
102  // Check if forward walk is in progress
103  if ((int)MA::RobotState->ComplexIndicators->ElapsedForwardWalkTime == 0)
104  return;
105 
106  // Create the surface analyzer
107  if ((MA::RobotState->ComplexIndicators->ElapsedForwardWalkTime >= 150*32) &&
108  !SurfaceAnalyzer.get())
109  {
110  SurfaceAnalyzer.reset(new MASurfaceAnalyzer(150));
112  }
113  // Update the surface analyzer
114  if (SurfaceAnalyzer.get())
115  {
116  SurfaceAnalyzer->AddSamples(*MA::RobotState);
117  }
118  if (SurfaceAnalyzer.get() && SurfaceAnalyzer->IsValid() &&
119  RecognizedSurface == (int)MA::UnknownFloor)
120  {
121  // Do the initial surface analysis
122  MC::FloatList SurfaceFeatureVector = SurfaceAnalyzer->GetFeatureVector();
123 
124  MCPrintContainerAsFloats(SurfaceFeatureVector, "Surface feature vector", 4);
125  // Add the surface vector to data collection as custom data
126  MC::BinaryDataSPtr BinaryData(MCEncodeToBinaryData(SurfaceFeatureVector));
127  MC::FloatList Confidence;
128 
129  MA::DataCollector->AddCustomDataToActiveJob(MA::FloorSurfaceModelID, MA::FloorSurfaceVectorID,
130  *BinaryData);
131  // Recognize the surface
132  RecognizedSurface = (int)MA::ClassifierModels->Recognize(MA::FloorSurfacesID, SurfaceFeatureVector,
133  Confidence);
134  RecognizedCurrentSurface = RecognizedSurface;
135  if (RecognizedSurface == (int)MA::WoodFlooring)
136  MC_LOG("Recognized: wood flooring");
137  else
138  if (RecognizedSurface == (int)MA::Field)
139  MC_LOG("Recognized: field");
140  else
141  if (RecognizedSurface == (int)MA::CarpetedFloor)
142  MC_LOG("Recognized: carpeted floor");
143  else
144  if (RecognizedSurface == (int)MA::Carpet)
145  {
146  MA_RANDOM_POINT_1(Reaction, 1, 5);
147 
148  MC_LOG("Recognized: carpet");
149  if (Reaction == 5)
150  {
151  // Calculate a random remaining walk duration before the happy feedback
152  MA_RANDOM_POINT_1(Divider, 1, 9);
153  int Duration = MA::RobotState->Goals->DesiredForwardWalkDuration-
154  MA::RobotState->ComplexIndicators->ElapsedForwardWalkTime;
155 
156  Duration = (int)((float)Duration / Divider)+MA::RobotState->ComplexIndicators->ElapsedForwardWalkTime;
157  MA::RobotState->Goals->DesiredForwardWalkDuration = Duration;
158  MA::RobotState->Goals->HappyOnCarpetFeedback = 1;
159  }
160  } else
161  if (RecognizedSurface == (int)MA::Vinyl)
162  MC_LOG("Recognized: vinyl");
163  else
164  if (RecognizedSurface == (int)MA::Tiles)
165  {
166  MC_LOG("Recognized: tiles");
167  } else {
168  MC_LOG("Recognized: unknown");
169  }
170  // Add the recognized surface to data collection as custom data
171  BinaryData.reset(MCEncodeToBinaryData(RecognizedSurface));
172  MA::DataCollector->AddCustomDataToActiveJob(MA::FloorSurfaceModelID, MA::RecognizedFloorSurfaceID,
173  *BinaryData);
174  // Start to wait the owner feedback about the actual surface
176  SurfaceRecognitionTimer->Start();
177  } else
178  // The surface is recognized after every ~2400 msec when the robot body is in the same posture.
179  if (SurfaceAnalyzer.get() && SurfaceAnalyzer->IsValid() &&
180  SurfaceRecognitionTimer->Timeout())
181  {
182  SurfaceRecognitionTimer->Start();
183  // Do the continuous surface analysis to detect any anomalies
184  MC::FloatList SurfaceFeatureVector = SurfaceAnalyzer->GetFeatureVector();
185  MC::FloatList Confidence;
186 
187  MCPrintContainerAsFloats(SurfaceFeatureVector, "Surface feature vector", 4);
188  RecognizedCurrentSurface = (int)MA::ClassifierModels->Recognize(MA::FloorSurfacesID,
189  SurfaceFeatureVector, Confidence);
190  if (RecognizedCurrentSurface == (int)MA::WoodFlooring)
191  MC_LOG("Recognized: wood flooring");
192  else
193  if (RecognizedCurrentSurface == (int)MA::Field)
194  MC_LOG("Recognized: field");
195  else
196  if (RecognizedCurrentSurface == (int)MA::Carpet)
197  MC_LOG("Recognized: carpet");
198  else
199  if (RecognizedCurrentSurface == (int)MA::Vinyl)
200  MC_LOG("Recognized: vinyl");
201  else
202  if (RecognizedCurrentSurface == (int)MA::Tiles)
203  {
204  MC_LOG("Recognized: tiles");
205  } else {
206  MC_LOG("Recognized: unknown");
207  }
208  }
209 }
210 
211 
213 {
214  bool Failed = MA::RobotState->ComplexIndicators->BodyOutOfWalkingRange > 90;
215 
216  Failed = Failed || MA::RobotState->Torso->CycleTime > MA::WalkCycleTimeMax;
217  if (MA::RobotState->Torso->CycleTime > MA::WalkCycleTimeWarning)
218  {
219  MC_WARNING("Cycle time is over the safe level (%d > %d)",
220  (int)MA::RobotState->Torso->CycleTime, MA::WalkCycleTimeWarning);
221  } else
222  if (MA::RobotState->Torso->CycleTime > MA::WalkCycleTimeMax)
223  {
224  // The freefall behavior must be created in advance to block the MABodyStateMaster behavior after
225  // MAWalkMaster fails.
226  MABEHAVIOR_CREATE(MAWalkFreefall, nullptr, true);
227  MC_WARNING("Cycle time is over the emergency level (%d > %d)",
228  (int)MA::RobotState->Torso->CycleTime, MA::WalkCycleTimeMax);
229  }
230  if (!MA::RobotState->BodyMotion->IsBodyRollInWalkRange())
231  {
232  // The freefall behavior must be created in advance to block the MABodyStateMaster behavior after
233  // MAWalkMaster fails.
234  MABEHAVIOR_CREATE(MAWalkFreefall, nullptr, false);
235  }
236  return Failed;
237 }
238 
239 
241 {
242  // It may happen that the robot falls down, but this master behavior does not fail...
243  if (!MA::RobotState->BodyMotion->IsBodyRollInWalkRange() || MABEHAVIOR_EXISTS(MAAvoidObstacleMaster))
244  {
245  MABEHAVIOR_CREATE(MAWalkFreefall, nullptr, false);
246  }
248 }
249 
250 
252 {
253  if (WalkStartTimestamp != -1 && GetState() == MABehavior::Activated)
254  {
255  int ElapsedTime = MCMax(0, GetElapsedActivatedStateTime()-WalkStartTimestamp);
256 
257  if (state.Goals->DesiredForwardWalkDuration > 0)
258  {
259  state.ComplexIndicators->ElapsedForwardWalkTime = ElapsedTime;
260  } else {
261  state.ComplexIndicators->ElapsedBackwardWalkTime = ElapsedTime;
262  }
263  } else {
264  if (state.Goals->DesiredForwardWalkDuration > 0)
265  {
266  state.ComplexIndicators->ElapsedForwardWalkTime = 0;
267  } else {
268  state.ComplexIndicators->ElapsedBackwardWalkTime = 0;
269  }
270  }
271  state.BodyMotion->Floor.Surface = RecognizedSurface;
272  state.BodyMotion->Floor.CurrentSurface = RecognizedCurrentSurface;
273 }
#define MA_RANDOM_POINT_1(_variable_name, _min, _max)
Set a random point with one value.
#define MABEHAVIOR_DELETE(_behavior)
Delete a behavior safely (mark it dirty if exists)
Definition: MABehavior.hpp:81
The head looks around behavior.
#define MABEHAVIOR_EXISTS(_behavior)
Check if a behavior exists.
Definition: MABehavior.hpp:74
int GetElapsedActivatedStateTime() const
Get the elapsed activated state time.
Definition: MABehavior.cpp:561
MA::DesiredConnectionMap DesiredConnections
Desired connection map to other behaviors.
Definition: MABehavior.hpp:766
Behavior base class.
Definition: MABehavior.hpp:157
#define MC_WARNING(...)
Warning macro.
Definition: MCLog.hpp:43
virtual void UpdateRobotState(MARobotState &state) override
Update the robot state.
Surface analyzer class.
virtual void FinishingActions() override
Perform actions when the behavior is being finished.
boost::scoped_ptr< MAComplexIndicators > ComplexIndicators
Complex indicators.
StateType GetState() const
Get the behavior state.
Definition: MABehavior.hpp:393
#define MABEHAVIOR_CREATE(_behavior, _master,...)
Create behaviors with custom constructor safely.
Definition: MABehavior.hpp:43
std::string MCGetClassName(T *instance=nullptr, const std::string &name_suffix="")
Get a class name.
Definition: MCDefs.hpp:627
Initial balance of the body before walk.
Avoid an abyss or an object while walking.
Freefall when the robot falls down while walking or caused by safety reasons.
boost::scoped_ptr< MAGoals > Goals
Goals.
boost::scoped_ptr< MABodyMotion > BodyMotion
Body motion.
Robot state updater base class.
virtual void ActivatedStateUpdate() override
Perform actions when the behavior is in activated state.
virtual void ActivatingActions() override
Perform actions when the behavior is being activated.
Simple timer class with microsecond precision.
Definition: MCTimer.hpp:59
Indicate the floor surface recognition period.
MCBinaryData * MCEncodeToBinaryData(const T &data, bool portable=true)
Encode a data into binary form.
const T MCMax(const U &container)
Get the maximal value of a container.
Wait for owner feedback about the real flooring surface.
virtual bool IsFailed() override
Whether the behavior is failed.
virtual MABehavior::StimulusLevelType GetCurrentStimulus() override
Get the current behavior stimulus.
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
Robot state.
void MCPrintContainerAsFloats(U &container, const std::string &message="", unsigned int digits=2)
Print a container to the output as float numbers.