Can one state appear in multiple state machine with AASM? - state-machine

Gem AASM supports multiple state machine per class with verion 4.3 or above. A unique state machine selector is used for each state machine in one class. Can one state appear in multiple state machine?
Here is an example. The state walking appears in both :move and :work. Is state walking all right? Or I have to name differently like: state walking_move and state waling_work.
class SimpleMultipleExample
include AASM
aasm(:move) do
state :standing, :initial => true
state :walking #<====
event :walk do
transitions :from => :standing, :to => :walking
end
end
aasm(:work) do
state :sleeping, :initial => true
state :walking #<====
event :start do
transitions :from => :sleeping, :to => :walking
end
end
end
Also can all initial state be the same such as initial_state in different state machine?

Related

Confusion About Implementing LeafSystem With Vector Output Port Correctly

I'm a student teaching myself Drake, specifically pydrake with Dr. Russ Tedrake's excellent Underactuated Robotics course. I am trying to write a combined energy shaping and lqr controller for keeping a cartpole system balanced upright. I based the diagram on the cartpole example found in Chapter 3 of Underactuated Robotics [http://underactuated.mit.edu/acrobot.html], and the SwingUpAndBalanceController on Chapter 2: [http://underactuated.mit.edu/pend.html].
I have found that due to my use of the cart_pole.sdf model I have to create an abstract input port due receive FramePoseVector from the cart_pole.get_output_port(0). From there I know that I have to create a control signal output of type BasicVector to feed into a Saturation block before feeding into the cartpole's actuation port.
The problem I'm encountering right now is that I'm not sure how to get the system's current state data in the DeclareVectorOutputPort's callback function. I was under the assumption I would use the LeafContext parameter in the callback function, OutputControlSignal, obtaining the BasicVector continuous state vector. However, this resulting vector, x_bar is always NaN. Out of desperation (and testing to make sure the rest of my program worked) I set x_bar to the controller's initialization cart_pole_context and have found that the simulation runs with a control signal of 0.0 (as expected). I can also set output to 100 and the cartpole simulation just flies off into endless space (as expected).
TL;DR: What is the proper way to obtain the continuous state vector in a custom controller extending LeafSystem with a DeclareVectorOutputPort?
Thank you for any help! I really appreciate it :) I've been teaching myself so it's been a little arduous haha.
# Combined Energy Shaping (SwingUp) and LQR (Balance) Controller
# with a simple state machine
class SwingUpAndBalanceController(LeafSystem):
def __init__(self, cart_pole, cart_pole_context, input_i, ouput_i, Q, R, x_star):
LeafSystem.__init__(self)
self.DeclareAbstractInputPort("state_input", AbstractValue.Make(FramePoseVector()))
self.DeclareVectorOutputPort("control_signal", BasicVector(1),
self.OutputControlSignal)
(self.K, self.S) = BalancingLQRCtrlr(cart_pole, cart_pole_context,
input_i, ouput_i, Q, R, x_star).get_LQR_matrices()
(self.A, self.B, self.C, self.D) = BalancingLQRCtrlr(cart_pole, cart_pole_context,
input_i, ouput_i,
Q, R, x_star).get_lin_matrices()
self.energy_shaping = EnergyShapingCtrlr(cart_pole, x_star)
self.energy_shaping_context = self.energy_shaping.CreateDefaultContext()
self.cart_pole_context = cart_pole_context
def OutputControlSignal(self, context, output):
#xbar = copy(self.cart_pole_context.get_continuous_state_vector())
xbar = copy(context.get_continuous_state_vector())
xbar_ = np.array([xbar[0], xbar[1], xbar[2], xbar[3]])
xbar_[1] = wrap_to(xbar_[1], 0, 2.0*np.pi) - np.pi
# If x'Sx <= 2, then use LQR ctrlr. Cost-to-go J_star = x^T * S * x
threshold = np.array([2.0])
if (xbar_.dot(self.S.dot(xbar_)) < 2.0):
#output[:] = -self.K.dot(xbar_) # u = -Kx
output.set_value(-self.K.dot(xbar_))
else:
self.energy_shaping.get_input_port(0).FixValue(self.energy_shaping_context,
self.cart_pole_context.get_continuous_state_vector())
output_val = self.energy_shaping.get_output_port(0).Eval(self.energy_shaping_context)
output.set_value(output_val)
print(output)
Here are two things that might help:
If you want to get the state of the cart-pole from MultibodyPlant, you probably want to be connecting to the continuous_state output port, which gives you a normal vector instead of the abstract-type FramePoseVector. In that case, your call to get_input_port().Eval(context) should work just fine.
If you do really want to read the FramePoseVector, then you have to evaluate the input port slightly differently. You can find an example of that here.

Sub_block base_address override?

Is there a way to assign a different base_address to the sub_blocks of a sub_block?
I have a case where I have something like this:
dut.rb:
sub_block ipBlock base_address: 0x11000000
and so the registers at this level all start with 0x110000000
But ipBlock also has its own sub_blocks:
ipblock.rb:
sub_block subIPBlock base_address: 0x0
with its own registers that due to an interface difference require a 0 base_address.
Unfortunately, when I add registers to subIPBlock they still have the base address of the top-level ipBlock:
sub_ipblock.rb:
add_reg :reg0, 0x0, 16, reset: 0xFFFF ...
Is there is a way to easily reassign the base address of the sub_block of a sub_block?
I believe you can use sub-block domains to achieve what you want.
sub_block :subx2, class_name: "SubX", base_address: { ips: 0x2000_0000, ahb: 0x3000_0000 }
dut.subx1.reg1.address(domain: :ips) # => 0x2000_0200
dut.subx1.reg1.address(domain: :ahb) # => 0x3000_0200
regards
In addition to the other answer, also note that reg.offset will return the block relative address, which it sounds like you want here.
All Origen drivers should override the register's address when an :address option is given, so within your model you could implement a read/write register method to add an :address option:
def write_register(reg, options = {})
if your_criteria_to_use_local_address
options[:address] = reg.offset
end
dut.write_register(reg, options) # Handover for original write
end
You could also force/override the base address within your model by implementing the following method:
def reg_base_address(options = {})
0
end
Finally, note that when using the domains per #rchitect-of-info's answer, you can define two domains when you instantiate a parent sub-block, then when you instantiate a child of that sub-block you can pick which of the available domains it is assigned to.
See this example from the documentation linked to in the other answer:
$dut.subx2.suby1.reg1.address # => 0x2000_0300
$dut.subx2.suby2.reg1.address # => 0x3000_0300

How to generate random json diffs in haskell quickcheck

I need to test the framework that can observe the state of some json http resource (I'm simplifying a bit here) and can send information about its changes to message queue so that client of service based on this framework could reconstruct actual state without polling http resourse.
It's easy to formulate properties for such framework. Let say we have a list of triples State, Diff, Timestamp
gen_states = [(gs1, Nothing, t1), (gs2, Just d1-2, t2), (gs3, Just d2-3, t3), (gs4, Just d3-4, t4)]
and after mirroring all this state to the http resource (used as test double) we gathered [rs1, rd1-2, rd2-3] where r stands for received.
apply [rd1-2, rd2-3] rs1 == gs4 final states should be the same the same
Also let's say that polling interval was more than the time difference between changes t3 - t2 than we can loose the diff d2-3 but the state still have to be consisted with state that was at previous polling gs2 for example. So we can miss some changes, but the received state should be consisted with some of the previous states that was no later than one polling interval before.
The question is how to create a generator that generates random diffs for json resource, given that resource is always an array of objects that all have id key.
For example initial state could look like that
[
{"id": "1", "some": {"complex": "value"}},
{"id": "2", "other": {"simple": "value"}}
]
And the next state
[
{"id": "1", "some": {"complex": "value"}},
{"id": "3", "other": "simple_value"}
]
Which should make diff like
type Id = String
data Diff = Diff {removed :: [Id], added :: [(Id, JsonValue)]}
added = [aesonQQ| {"id": 3, "other": "simple_value"} |]
Diff [2] [added]
I've tried to derive Arbitrary for aeson Object, but got this
<interactive>:15:1: warning: [-Wmissing-methods]
• No explicit implementation for
‘arbitrary’
• In the instance declaration for
‘Arbitrary
(unordered-containers-0.2.8.0:Data.HashMap.Base.HashMap
Data.Text.Internal.Text Value)’
But even if I would accomplished that how would I specify that added should have new unique id?

Origen::Parameter sets getting erased upon $dut re-init

I create many test interface parameters during the $dut initialization. The app inits the model in either 'load' or 'import' mode, as we get many sources of info from 3rd parties. For parameters, the source is native Ruby so regardless of the init method (load or import) the code is required like this:
send modeling_method, model_path # load_params or import_params
Here is that method(s):
def load_params(path)
Origen.log.info("PPEKit: Modeling parameters from #{path}")
require path.to_s.chomp('.rb')
Origen.log.info("PPEKit: Modeling of parameters complete")
end
alias_method 'import_params', 'load_params'
Here is the content of the file required above:
Origen.top_level.define_params :default do |params|
params.bist.override = 1
params.bist.lev_equ_set = 1
params.bist.lev_spec_set = 1
params.bist.levset = 1
params.bist.seqlbl = 'mbist_cpu_hr_vnom_burst'
params.bist.override_tim_spec_set = 'bist_25Mhz'
params.bist.override_timset = '1,1,1,1,1,1,1,1'
params.bist.site_control = 'parallel:'
params.bist.site_match = 2
end
I can see them at the end of my $dut initialization during execution of the command 'origen p myflowfile.rb':
[5] pry(#<PPEKit::Product>)> $dut.params
=> {:bist=>
{:override=>1,
:lev_equ_set=>1,
:lev_spec_set=>1,
:levset=>1,
:seqlbl=>"mbist_cpu_hr_vnom_burst",
:override_tim_spec_set=>"bist_25Mhz",
:override_timset=>"1,1,1,1,1,1,1,1",
:site_control=>"parallel:",
:site_match=>2}}
However, when Origen transitions to the test interface code, the params are not accessible:
[1] pry(#<STP::Interface>)> $dut.params
=> #<Origen::Parameters::Missing:0x002aaab22dc378
#owner=<Model/Controller: PPEKit::Product:23456337817000/PPEKit::ProductController:23456355062960>>
I can, however, see other parts of the $dut model such as pins and sub_blocks:
[2] pry(#<STP::Interface>)> $dut.sub_blocks
=> {"block0"=><Model: PPEKit::Product::Block0:23456336916760>,
"block1"=><Model: PPEKit::Product::Block1:23456336907380>,
"block2"=><Model: PPEKit::Product::Block2:23456336841100>,
It just seems like they are getting erased sometime between the model init and the test flow generation. So I put a breakpoint in the 'on_load_target' callback, and saw different results each time the breakpoint was hit. On the first break, the params were there and on subsequent breaks they were not.
75: def on_load_target
=> 76: binding.pry
77: to_origen(path: vendor_path.to_s, instantiate_level: :sub_block) if #import
78: end
[1] pry(#<PPEKit::Product>)> $dut.params
=> {:bist=>
{:override=>1,
:lev_equ_set=>1,
:lev_spec_set=>1,
:levset=>1,
:seqlbl=>"mbist_ccx_hr_vnom_burst",
:override_tim_spec_set=>"bist_25Mhz",
:override_timset=>"1,1,1,1,1,1,1,1",
:site_control=>"parallel:",
:site_match=>2}}
[2] pry(#<PPEKit::Product>)>
Frame number: 0/25
From: /users/user/origen/ppekit/lib/ppekit/product.rb # line 76 PPEKit::Product#on_load_target:
75: def on_load_target
=> 76: binding.pry
77: to_origen(path: vendor_path.to_s, instantiate_level: :sub_block) if #import
78: end
[1] pry(#<PPEKit::Product>)> $dut.params
=> #<Origen::Parameters::Missing:0x002aaab9f3ad48
#owner=<Model/Controller: PPEKit::Product:23456377300040/PPEKit::ProductController:23456379739240>>
I believe there could be 2 issues here:
1) The repeated initialization of the $dut during test flow generation, documented here
2) The emptying of the parameter set hash, which is due to issue #1 (and some Parameter set initialization code
I believe it has something to do with the parameter #owner being defined as the $dut instance during the parameter definition and #owner being re-defined as the $dut ProductController instance on subsequent queries of the parameters.
thx
The problem here is that the parameters are ultimately getting loaded by calling require 'some_file.rb'.
Whenever the target is internally re-loaded, Ruby hits the line again but does not do anything since it knows that it has already required that file and effectively skips over that line.
Changing it to load 'some_file.rb' will force it to execute the file every time.

TCP Stack Sending A Mbuf Chain: where is the loop?

I am new to BSD TCP stack code here, but we have an application that converted and uses BSD TCP stack code in the user mode. I am debugging an issue that this application would hold (or not sending data) in a strange situation. I included part of the related callstack below.
Before calling sosend in uipc_socket, I have verified that the length stored in the top, _m0->m_pkthdr.len has the right value. The chain should hold 12 pieces of TCP payload each with 1368 bytes long. In the end, my callback function only got called 10 times instead of 12 and the 10 smaller mbuf chains contains less payload data after they were combined.
I checked each function in the call stack and I could not find a loop anywhere to iterate through from the head to the end of the mbuf chain as I expected. Only loops I could find was the nested do ... while() loops in sosend_generic of uipc_socket.c, however, my code path only executed the loop once, since the resid was set to 0 immediately after the (uio == NULL) check.
\#2 0x00007ffff1acb868 in ether_output_frame (ifp=0xbf5f290, m=0x7ffff7dfeb00) at .../freebsd_plebnet/net/if_ethersubr.c:457
\#3 0x00007ffff1acb7ef in ether_output (ifp=0xbf5f290, m=0x7ffff7dfeb00, dst=0x7fffffff2c8c, ro=0x7fffffff2c70) at .../freebsd_plebnet/net/if_ethersubr.c:429
\#4 0x00007ffff1ada20b in ip_output (m=0x7ffff7dfeb00, opt=0x0, ro=0x7fffffff2c70, flags=0, imo=0x0, inp=0x7fffd409e000) at .../freebsd_plebnet/netinet/ip_output.c:663
\#5 0x00007ffff1b0743b in tcp_output (tp=0x7fffd409c000) at /scratch/vindu/ec_intg/ims/src/third-party/nse/nsnet.git/freebsd_plebnet/netinet/tcp_output.c:1288
\#6 0x00007ffff1ae2789 in tcp_usr_send (so=0x7fffd40a0000, flags=0, m=0x7ffeda1b7270, nam=0x0, control=0x0, td=0x7ffff1d5f3d0) at .../freebsd_plebnet/netinet/tcp_usrreq.c:882
\#7 0x00007ffff1a93743 in sosend_generic (so=0x7fffd40a0000, addr=0x0, uio=0x0, top=0x7ffeda1b7270, control=0x0, flags=128, td=0x7ffff1d5f3d0) at .../freebsd_plebnet/kern/uipc_socket.c:1390
\#8 0x00007ffff1a9387d in sosend (so=0x7fffd40a0000, addr=0x0, uio=0x0, top=0x7ffeda1b7270, control=0x0, flags=128, td=0x7ffff1d5f3d0) at .../freebsd_plebnet/kern/uipc_socket.c:1434

Resources