Geofence with pymavlink or dronekit-python - python

I'm trying to set fence for the copter using dronekit-python.I found command MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION in this document.
But it doesn't work when I use the vehicle.message_factory.command_long_send (which is the function command_long_send in class MAVLink from the file ardupilotmega.py actually ), I cannot find mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION either (so I use integer 5003 directly).
After reading the source code of ardupilotmega.py, I found that there is a function called fence_point_send, so can anyone tell me how to use it? How can I set the geofence just like what Misson Planner do with python?

You should use this command MAV_CMD_DO_FENCE_ENABLE to enable or disable geo-fence.
geo-fence has two parameters.
FENCE_ALT_MAX: The maximum altitude that the vehicle can reach.
FENCE_RADIUS : The maximum circle radius the vehicle can move in.
To change the parameters in code, you should use a function like PARAM_SET and pass the name and value for the parameter.
P.S: You can do all that using GCS like Mission Planner, APM Planner2 or Mavproxy.

Related

Dymos: How can I record and visualize subsystem inputs/outputs?

I am trying to optimize a similar problem as the "Commercial Aircraft Range Maximization by Differential Inclusion" example using Dymos.
Is there a way to see the variation of (for example) the lift coefficient for the optimized trajectory?
It isn't a state or control variable, just some intermediate variable within the problem definition.
I know there is the .add_recorder() method, but I'm not sure how to use it or whether it is the right solution.
So the timeseries object captures time series data regardless of the transcription used. By default, it includes the "problem" variables (states, controls, input and design parameters, and time).
To record other outputs in your ODE, use the add_timeseries_output method on Phase. It is documented here: https://openmdao.github.io/dymos/feature_reference/timeseries.html
For the aircraft example in Dymos, you can add the line:
phase.add_timeseries_output('aero.CL', units=None, shape=(1,))
Which will add a new output traj.phase0.timeseries.CL. Theres a few things to note here:
dotted variable names aren't allowed. So while aero.CL is the path of the lift coefficient relative to the top of the ODE, it will be recorded in the timeseries as CL. If this will cause name collisions, you can override the timeseries name using the output_name argument.
Currently we can't use introspection to automatically determine the units and shape of the variable to be added to the timeseries (we're working on that). So it's good practice to specify the units and shape when adding the timeseries output (and mandatory if the units are not None or the shape is not (1,).
So adding that above line to the commercial aircraft example, and adding the following to our simplified plot maker:
plot_results([('traj.phase0.timeseries.states:range', 'traj.phase0.timeseries.states:alt',
'range (NM)', 'altitude (kft)'),
('traj.phase0.timeseries.time', 'traj.phase0.timeseries.states:mass_fuel',
'time (s)', 'fuel mass (lbm)'),
('traj.phase0.timeseries.time', 'traj.phase0.timeseries.CL',
'time (s)', 'lift coefficient')],
title='Commercial Aircraft Optimization',
p_sol=p, p_sim=exp_out)
Make the following plot:
You can use an OpenMDAO recorder to store timeseries outputs in a recorded database file. For instance, to add a recorder to the optimization driver (which will save at every iteration), you'd do something like this:
p.driver.add_recorder(rec)
p.driver.recording_options['record_desvars'] = True
p.driver.recording_options['record_responses'] = True
p.driver.recording_options['record_objectives'] = True
p.driver.recording_options['record_constraints'] = True
p.driver.recording_options['includes'] = ['*timeseries*']
That last instruction will inform Dymos to record all of the outputs whose name includes "timeseries". FYI you can also add a recorder to the problem and only record the final values, instead of recording each iteration. This can save a good bit of filesize if you're not interested in the iteration history.

call function inside argument of a function in python

I am starting with python, and I am trying to understand the sample code that Phidget website give to me (I bought a Phidget Bridge 4 input where I have plug on 4 gauge cell). For my project I need to use python but not much use to it.
To read only one channel, sol only one gauge cell with my Phidget bridge, the website give me this code.
from Phidget22.Phidget import *
from Phidget22.Devices.VoltageRatioInput import *
import time
def onVoltageRatioChange(self, voltageRatio):
print("VoltageRatio: " + str(voltageRatio))
def main():
voltageRatioInput0 = VoltageRatioInput()
voltageRatioInput0.setOnVoltageRatioChangeHandler(onVoltageRatioChange)
voltageRatioInput0.openWaitForAttachment(5000)
time.sleep(5)
voltageRatioInput0.close()
main()
There is the function def onVoltageRatioChange(self, voltageRatio): which takes 2 arguments, self and voltageRatio, and this function is used inside setOnVoltageRatioChangeHandler(onVoltageRatioChange) with no argument. What I mean, it's that I do not get why we give as an argument onVoltageChange (which is normally a function) to the function setOnVoltageRatioChangeHandler...
It someone could explain it to me, it could help me to build my own code... at least try..
thank you
Phidget22 knows how to detect a voltage ratio change, but it doesn't know what you want to do with it: maybe you want to sound an alarm. maybe you want to send an email with the new ratio. maybe you just want to print it to the screen.
So it uses setOnVoltageRatioChangeHandler to ask you what you would like to do once it detects this voltage change, saying "hey, if you'll give me a function that takes a voltage ratio, I'll call it when I detect a change" then you can do:
setOnVoltageRatioChangeHandler(soundTheAlarm)
or
setOnVoltageRatioChangeHandler(sendAnEmail)
or:
setOnVoltageRatioChangeHandler(printToScreen)
The supplied onVoltageRatioChange will just print the new value to the screen.
Generally, passing a function as an argument is a great way to give flexibility in the way events are handled. It's basically saying "I know how to detect a certain situation or get a certain value. You let me know what you want me to do once I do"

LLDB: Set breakpoint at offset from function start using python api

I have a lldb python module with a simple setup:
def __lldb_init_module (debugger, dict):
target = debugger.GetSelectedTarget()
target.DeleteAllBreakpoints()
process = target.GetProcess()
I can easily set a breakpoint at the start of a function using:
breakpoint = target.BreakpointCreateByName("functionName", "moduleName")
breakpoint.SetScriptCallbackFunction( "python_module.bp_hit" )
and I know this works because my bp_hit function is called correctly.
However, I really need the breakpoint set at X number of bytes from the start of the address of functionName. If I knew the address of the functionName, I could simply add X to the address and use BreakpointCreateByAddress.
What is the python code that will provide me the address of the functionName?
Use SBTarget::FindFunctions to find the SBSymbolContext(s) that match a your function name. That returns a list of SBSymbolContext matches (since there may be more than one.) SBSymbolContext::GetStartAddress will give you an SBAddress for the start of that symbol. Then use SBAddress::OffsetAddress to add your offset. There is a SBTarget::CreateBreakpointByAddress but annoyingly enough it only takes an lldb::addr_t not an SBAddress. You can get an lldb::addr_t from an SBAddress with SBAddress::GetLoadAddress() passing in your target.
An alternative to Jim's answer is to use the FindSymbols function of SBTarget.

ROS frame transformation (camera to base)

I am working with Baxter robot and what I am trying to do is get the position of an object using augmented reality markers and move the hand to that position in order to grasp it.
I am using the ar_tools package to get the position/orientation of the object, but that with respect to the head_camera which I am using. The last couple of days I've been experimenting with how to change that reference frame (head_camera) to the base frame as this frame is used by moveit to make the plans. I have tried to set the frame_id of the header of the message I receive from the ar_tools manually to 'base':
pose_target.header.frame_id = 'base'
but the position and orientation I am getting are still WRT the head_camera. I also tried to do:
self.tl.lookupTransform("/base", "/head_camera", self.t)
where self.t = self.tl.getLatestCommonTime("/head_camera", "/base"), but I was getting an extrapolation error. It was something like
the transformation requires to extrapolate in the past
(I can't really remember now and I'm not in the lab.) Then I thought I might need to run the lookupTransform from the head_cam to head, from head to torso and from torso to Baxter's base.
Could someone guide me on how to change the frame of the marker of the ar_tools from head_camera to base?
Also, for the extrapolation error, is there a way to do this in a static way?
There is a slightly more straightforwards way to do this, presuming you're reviving a PoseStamped message from ar_tools:
on_received_pose(pose):
'''
Handler for your poses from ar_tools
'''
if self.tl.waitForTransform(pose.header.frame_id, "/base", pose.header.stamp, rospy.Duration(0.1)): # this line prevents your extrapolation error, it waits up to 0.1 seconds for the transform to become valid
transd_pose = self.tl.transformPose("/base",pose)
# do whatever with the transformed pose here
else:
rospy.logwarn('Couldn\'t Transform from "{}" to "/base" before timeout. Are you updating TF tree sufficiently?'.format(pose.header.frame_id))
You're getting that extrapolation error likely because the transform network wasn't fully formed at the time you got your first message; tf refuses to extrapolate, it will only interpolate, so if you haven't received at least one transform message for every frame both before and after (or exactly at) the timestamp you're trying to transform to, it will throw an exception. That added if statement checks to see if it can actually perform the transform before trying to do so. You could of course also just surround the transformPose() call in a try/catch block instead, but I feel that for tf this makes it more explicit what you're trying to do.
In general, check out the simple ROS tf Python Tutorial for more examples/modes of operation.

FMU FMI simulation, no modification of results when setting certain type of parameter

I developed for the example a simple Modelica model based on the fluid library of the MSL. I connected a MassFlowSource with a pipe and a Boundary_PT as sink function as in the picture below:
http://www.casimages.com/img.php?i=14061806120359130.png
I generate a FMU package with OpenModelica (in mode model-exchange).
I manage this FMU package with python with the code below:
import pyfmi, os
from pyfmi import load_fmu
myModel = load_fmu('PathToFolder\\test3.fmu')
res1 = myModel.simulate() # First simulation with m_flow in source set to [1] Kg/s
x = myModel.get('boundary1.m_flow') # Mass flow rate of the source
y = myModel.get('pipe.port_a.m_flow') # Mass flow rate in pipe
print x, y
myModel.set('boundary1.m_flow', 2)
option = myModel.simulate_options()
option['initialize'] = False # Need to initialize the simulation
res2 = myModel.simulate(options = option) # Second simulation with m_flow in source set to [2] Kg/s
x = myModel.get('boundary1.m_flow') # Mass flow rate of the source
y = myModel.get('pipe.port_a.m_flow') # Mass flow rate in pipe
print x, y
os.system('pause')
The objective is to show a problem when you change a parameter in the model, here the "m_flow" variable in source component. This new set to "2" should change the "m_flow" in pipe but it does not.
Results: In the first simulation the both "m_flow" are gotten to "1" and it's normal because the model is set like this. In the second simulation, I set the parameter to "2" in the source but the pipe "m_flow" stay to "1" (It should be "2").
http://www.casimages.com/img.php?i=140618060905759619.png
The model of the fluid source in Modelica is this one (only our interesting part):
equation
if not use_m_flow_in then
m_flow_in_internal = m_flow;
end if;
connect(m_flow_in, m_flow_in_internal);
I think the FMU don't consider parameter when they are in a if-condition. For me it's a problem because I need to manage FMU and to be sure that if I set a parameter, the simulation will use this new set. How be sure that FMU/FMI works well? Where is the exhaustive list with the type of parameters we can't manage in FMU?
I already know that parameters which change the number of equations can't be consider in FMU management (idem for variables which change the index of DAEs).
Note that OpenModelica has a concept of structural parameters and the Evaluate=true annotation. For example, if a parameter is used as an array dimension, it might be evaluated to an Integer value. All uses of that parameter will use the evaluated value, as if it was a constant.
Rather than including a picture of the diagram, the Modelica source code would have been easier to look at in order to find out what OpenModelica did to the system.
I suspect a parameter was evaluated. If you generate non-FMU code, you could inspect the modelName_init.xml generated by OpenModelica and find the entry for a parameter and look for the property isValueChangeable.
You could also use OMEdit to debug the system and view the initial equation (generate the executable including debug information). File->Open Transformations File, then select the modelName_info.xml file. Search for the variable you tried to change and go to the initial equation that defined it. It could very well be that a start-value (set by PyFMI) is ignored because it is not needed to produce a solution.
whenever you try to set new values to the parameter,
Follow these steps:
1.Reset the model
2.set new values for the parameter
3.Simulate the model.
I am not familiar with PyFMI, but I kinda encountered the same situation before. You could try a few things below.
Try to terminate/free the instant after your first sim.
As most parameters could not be changed after init, you could make that parameter as an input connector, so that this specific parameter could be changed at any time.
(In FMU from Dymola) I also found that if that parameter involves in your initial nonlinear system of equation, then you will get an error "the model could not be initialized" if you try to init the model on the same instant.

Categories

Resources