1 /* User plug-in point for simulator customizations
2 Copyright (C) 2005-2008, Jonathan Bachrach, Jacob Beal, and contributors
3 listed in the AUTHORS file in the MIT Proto distribution's top directory.
5 This file is part of MIT Proto, and is distributed under the terms of
6 the GNU General Public License, with a linking exception, as described
7 in the file LICENSE in the MIT Proto distribution's top directory. */
9 // This file is where to make all of the small changes to adapt
10 // a spatial computer to the needs of a particular user.
11 // It's a separate file so that the core files won't change often.
12 // In particular, it is the only place that should need to be
13 // modified in order to integrate a new layer with the body.
16 #include "spatialcomputer.h"
17 #include "customizations.h"
18 #include "basic-hardware.h"
19 #include "simpledynamics.h"
20 #include "unitdiscradio.h"
22 #include "odedynamics.h"
25 /*****************************************************************************
26 * DEVICE DISTRIBUTIONS *
27 *****************************************************************************/
28 class UniformRandom
: public Distribution
{
30 UniformRandom(int n
, Rect
* volume
) : Distribution(n
,volume
) {}
31 virtual BOOL
next_location(METERS
*loc
) {
32 loc
[0] = urnd(volume
->l
,volume
->r
);
33 loc
[1] = urnd(volume
->b
,volume
->t
);
34 if(volume
->dimensions()==3) {
35 Rect3
* r
= (Rect3
*)volume
;
36 loc
[2] = urnd(r
->f
,r
->c
);
43 class XGrid
: public Distribution
{
45 int rows
,columns
,layers
;
47 XGrid(int n
, Rect
* volume
) : Distribution(n
,volume
) {
49 if(volume
->dimensions()==3) {
50 layers
= (int)ceil(pow(n
*depth
*depth
/(width
*height
), 1.0/3.0));
51 rows
= (int)ceil(layers
*width
/depth
);
52 columns
= (int)ceil(n
/rows
/layers
);
54 rows
= (int)ceil(sqrt(n
)*sqrt(width
/height
));
55 columns
= (int)ceil(n
/rows
);
59 BOOL
next_location(METERS
*loc
) {
60 int l
= (i
%layers
), r
= (i
/layers
)%rows
, c
= (i
/(layers
*rows
));
61 loc
[0] = volume
->l
+ c
*width
/columns
;
62 loc
[1] = urnd(volume
->b
,volume
->t
);
63 loc
[2] = (volume
->dimensions()==3)?(((Rect3
*)volume
)->f
+l
*depth
/layers
):0;
69 class FixedPoint
: public UniformRandom
{
71 int fixed
; int n_fixes
;
73 FixedPoint(Args
* args
, int n
, Rect
* volume
) : UniformRandom(n
,volume
) {
77 METERS
* loc
= (METERS
*)calloc(3,sizeof(METERS
));
78 loc
[0]=args
->pop_number(); loc
[1]=args
->pop_number();
79 loc
[2]= (str_is_number(args
->peek_next()) ? args
->pop_number() : 0);
81 } while(args
->extract_switch("-fixedpt",FALSE
));
83 virtual ~FixedPoint() {
84 for(int i
=0;i
<n_fixes
;i
++) { free(fixes
.get(i
)); }
86 BOOL
next_location(METERS
*loc
) {
88 METERS
* src
= (METERS
*)fixes
.get(fixed
);
89 for(int i
=0;i
<3;i
++) loc
[i
]=src
[i
];
93 return UniformRandom::next_location(loc
);
98 class Grid
: public Distribution
{
100 int rows
,columns
,layers
;
102 Grid(int n
, Rect
* volume
) : Distribution(n
,volume
) {
104 if(volume
->dimensions()==3) {
105 layers
= (int)ceil(pow(n
*depth
*depth
/(width
*height
), 1.0/3.0));
106 rows
= (int)ceil(layers
*width
/depth
);
107 columns
= (int)ceil(n
/rows
/layers
);
109 rows
= (int)ceil(sqrt(n
)*sqrt(width
/height
));
110 columns
= (int)ceil(n
/rows
);
114 BOOL
next_location(METERS
*loc
) {
115 int l
= (i
%layers
), r
= (i
/layers
)%rows
, c
= (i
/(layers
*rows
));
116 loc
[0] = volume
->l
+ c
*width
/columns
;
117 loc
[1] = volume
->b
+ r
*height
/rows
;
118 loc
[2] = (volume
->dimensions()==3)?(((Rect3
*)volume
)->f
+l
*depth
/layers
):0;
124 class GridRandom
: public Grid
{
127 GridRandom(Args
* args
, int n
, Rect
* volume
) : Grid(n
,volume
) {
128 epsilon
= args
->pop_number();
130 BOOL
next_location(METERS
*loc
) {
131 Grid::next_location(loc
);
132 loc
[0] += epsilon
*((rand()%1000/1000.0) - 0.5);
133 loc
[1] += epsilon
*((rand()%1000/1000.0) - 0.5);
134 if(volume
->dimensions()==3) loc
[2] += epsilon
*((rand()%1000/1000.0) - 0.5);
140 class Cylinder
: public Distribution
{
143 Cylinder(int n
, Rect
* volume
) : Distribution(n
,volume
) {
144 r
= MIN(width
, height
) / 2;
146 BOOL
next_location(METERS
*loc
) {
147 loc
[0] = urnd(volume
->l
,volume
->r
);
148 flo theta
= urnd(0, 2 * 3.14159);
149 loc
[1] = r
* sin(theta
);
150 loc
[2] = r
* cos(theta
);
156 /*****************************************************************************
157 * CHOICE OF DISTRIBUTION *
158 *****************************************************************************/
159 void SpatialComputer::choose_distribution(Args
* args
, int n
) {
160 if(args
->extract_switch("-grideps")) { // random grid
161 distribution
= new GridRandom(args
,n
,volume
);
162 args
->extract_switch("-grid"); // with eps, -grid is a null operation
163 } else if(args
->extract_switch("-grid")) { // plain grid
164 distribution
= new Grid(n
,volume
);
165 } else if(args
->extract_switch("-xgrid")) { // grid w. random y
166 distribution
= new XGrid(n
,volume
);
167 } else if(args
->extract_switch("-fixedpt")) {
168 distribution
= new FixedPoint(args
,n
,volume
);
169 } else if(args
->extract_switch("-cylinder")) {
170 distribution
= new Cylinder(n
,volume
);
171 } else { // default is random
172 distribution
= new UniformRandom(n
,volume
);
177 /*****************************************************************************
179 *****************************************************************************/
180 class FixedTimer
: public DeviceTimer
{
181 SECONDS dt
, half_dt
, internal_dt
, internal_half_dt
;
184 FixedTimer(flo dt
, flo ratio
) {
185 this->dt
=dt
; half_dt
=dt
/2;
186 internal_dt
= dt
*ratio
; internal_half_dt
= dt
*ratio
/2;
189 void next_transmit(SECONDS
* d_true
, SECONDS
* d_internal
) {
190 *d_true
= half_dt
; *d_internal
= internal_half_dt
;
192 void next_compute(SECONDS
* d_true
, SECONDS
* d_internal
) {
193 *d_true
= dt
; *d_internal
= internal_dt
;
195 DeviceTimer
* clone_device() { return new FixedTimer(dt
,internal_dt
/dt
); }
196 void set_internal_dt(SECONDS dt
) {
198 internal_half_dt
= dt
/2;
199 this->dt
= internal_dt
/ratio
;
200 half_dt
= internal_dt
/(ratio
*2);
204 class FixedIntervalTime
: public TimeModel
, public HardwarePatch
{
207 flo ratio
; flo rvar
; // ratio is internal/true time
209 FixedIntervalTime(Args
* args
, SpatialComputer
* p
) {
210 sync
= args
->extract_switch("-sync");
211 dt
= (args
->extract_switch("-desired-period"))?args
->pop_number():1;
212 var
= (args
->extract_switch("-desired-period-variance"))
213 ? args
->pop_number() : 0;
214 ratio
= (args
->extract_switch("-desired-ratio"))?args
->pop_number():1;
215 rvar
= (args
->extract_switch("-desired-ratio-variance"))
216 ? args
->pop_number() : 0;
218 p
->hardware
.patch(this,SET_DT_FN
);
221 DeviceTimer
* next_timer(SECONDS
* start_lag
) {
222 if(sync
) { *start_lag
=0; return new FixedTimer(dt
,ratio
); }
223 *start_lag
= urnd(0,dt
);
224 flo p
= urnd(dt
-var
,dt
+var
);
225 flo ip
= urnd(ratio
-rvar
,ratio
+rvar
);
226 return new FixedTimer(MAX(0,p
),MAX(0,ip
));
228 SECONDS
cycle_time() { return dt
; }
229 NUM_VAL
set_dt (NUM_VAL dt
) {
230 ((FixedTimer
*)device
->timer
)->set_internal_dt(dt
);
236 /*****************************************************************************
237 * CHOICE OF TIME MODELS *
238 *****************************************************************************/
239 void SpatialComputer::choose_time_model(Args
* args
, int n
) {
240 time_model
= new FixedIntervalTime(args
,this);
244 /*****************************************************************************
246 *****************************************************************************/
247 // boot_layers is the one function that needs to know about all possible layers
248 // A layer that is not added at this time cannot be added layer; it may be
249 // added but not executed, though.
250 void SpatialComputer::choose_layers(Args
* args
, int n
) {
251 // select physics model
252 if(args
->extract_switch("-ODE")) {
254 uerror("Cannot use ODE: Compiled without ODE");
256 physics
= new ODEDynamics(args
,this,n
);
259 physics
= new SimpleDynamics(args
,this,n
);
261 addLayer(new DebugLayer(args
,this));
262 addLayer(new UnitDiscRadio(args
,this,n
)); // select network model
263 addLayer(new SimpleLifeCycle(args
,this));
264 addLayer(new PerfectLocalizer(this));
266 if(args
->extract_switch("-mote-io")) addLayer(new MoteIO(args
,this));