Package: bell-avr-libraries
AVR-Python-LibrariesInstallTo install the base package, run:pipinstallbell-avr-librariesAdditionally, themqttandserialextras are available if you want to use
the MQTT or PCC functionality.pipinstallbell-avr-libraries[mqtt,serial]UsageMQTTfrombell.avrimportmqttThese are MQTT utilities that are used to have a consistent messaging protocol
throughout all the AVR software modules.The first part of this are the payloads for the MQTT messages themselves. As AVR
exclusively uses JSON, these are allTypedDicts
that have all of the required fields for a message.Example:frombell.avr.mqtt.payloadsimportAvrPcmSetBaseColorPayloadpayload=AvrPcmSetBaseColorPayload((128,232,142,0))The second part of the MQTT libraries, is theMQTTModuleclass.
This is a boilerplate module for AVR that makes it very easy to send
and recieve MQTT messages and do something with them.Example:frombell.avr.mqtt.clientimportMQTTModulefrombell.avr.mqtt.payloadsimportAvrFcmVelocityPayload,AvrPcmSetServoOpenClosePayloadclassSandbox(MQTTModule):def__init__(self)->None:super().__init__()self.topic_map={"avr/fcm/velocity":self.show_velocity}defshow_velocity(self,payload:AvrFcmVelocityPayload)->None:vx=payload["vX"]vy=payload["vY"]vz=payload["vZ"]v_ms=(vx,vy,vz)print(f"Velocity information:{v_ms}m/s")defopen_servo(self)->None:payload=AvrPcmSetServoOpenClosePayload(servo=0,action="open")self.send_message("avr/pcm/set_servo_open_close",payload)if__name__=="__main__":box=Sandbox()box.run()Thetopic_mapdictionary is a class attribute that maps topics to subscribe to
and a function that will handle an incoming payload. Thepayloadargument
should match the appropriatePayloadclass for that topic.Additionally, themessage_cacheattribute is a dictionary that holds
a copy of the last payload sent by that module on a given topic. The keys are the
topic strings, and the values are the topic payloads.Utilsfrombell.avrimportutilsThese are general purpose utilities.Decoratorsfrombell.avr.utilsimportdecoratorsThere are 3 different function decorators available, which are helpful for MQTT
message callbacks. First is thetry_exceptdecorator, which wraps the
function in atry: except:statement and will log any exceptions to the console:@decorators.try_exceptdefassemble_hil_gps_message(self)->None:...Additionally, there is thereraiseargument, which can be set toTrueto raise
any exceptions that are encountered. This is helpful if you still want exceptions
to propagate up, but log them.There is an async version of this decorator as well with anasync_prefix.@decorators.async_try_except()asyncdefconnected_status_telemetry(self)->None:...The last decorator isrun_foreverwhich will run the wrapped function forever,
with a givenperiodorfrequency.@decorators.run_forever(frequency=5)defread_data(self)->None:...Timingfrombell.avr.utilsimporttimingHere is arate_limitfunction which take a callable and a
period or frequency, and only run the callable at that given rate.for_inrange(10):# add() will only run twicetiming.rate_limit(add,period=5)time.sleep(1)This works tracking calls to therate_limitfunction from a line number
within a file, so multiple calls torate_limitsay within a loop
with the same callable and period will be treated seperately. This allows
for dynamic frequency manipulation.Serialfrombell.avrimportserialThese are serial utilities that help facilitate finding and communicating
with the AVR peripherial control computer.Clientfrombell.avr.serialimportclientTheSerialLoopclass is a small wrapper around thepyserialserial.Serialclass which adds arunmethod that will try to read data from the serial device
as fast as possible.ser=client.SerialLoop()PCCfrombell.avr.serialimportclientThePeripheralControlComputerclass sends serial messages
to the AVR peripherial control computer, via easy-to-use class methods.importbell.avr.serial.clientimportbell.avr.serial.pccimportthreadingclient=bell.avr.serial.client.SerialLoop()client.port=portclient.baudrate=baudrateclient.open()pcc=bell.avr.serial.pcc.PeripheralControlComputer(client)client_thread=threading.Thread(target=client.run)client_thread.start()pcc.set_servo_max(0,100)Portsfrombell.avr.serialimportportsHere is alist_serial_portsfunction which returns a list of detected serial
ports connected to the system.serial_ports=ports.list_serial_ports()# ["COM1", "COM5", ...]DevelopmentInstallpoetryand runpoetry install --extras mqtt --extras serialto install of the dependencies
inside a virtual environment.Build the auto-generated code withpoetry run python build.py. From here,
you can now produce a package withpoetry build.To add new message definitions, add entries to thebell/avr/mqtt/messages.jsoncfile.
The 3 parts of a new message are as follows:"topic": This is the full topic path for the message. This must be all lower case and
start with "avr/"."payload": These are the keys of the payload for the message.
This is a list of key entries (see below)."docs": This is an optional list of Markdown strings that explains what this
message does. Each list item is a new line.The key entries for a message have the following elements:"key": This is the name of the key. Must be a valid Python variable name."type": This is the data type of the key such asTuple[int, int, int, int].
Must be a valid Python type hint. Otherwise, this can be a list of more
key entries, effectively creating a nested dictionary."docs": This is an optional list of Markdown strings that explains what the
key is. Each list item is a new line.Thebell/avr/mqtt/schema.jsonfile will help ensure the correct schema is maintained,
assuming you are using VS Code.MQTT DocumentationData TypesAvrApriltagsRawTags"id"(int):
The ID of the AprilTag"pos"(AvrApriltagsRawTagsPos)"rotation"(Tuple[Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]]):
The 3x3 rotation matrixAvrApriltagsRawTagsPos"x"(float):
The position in meters of the camera relative to the AprilTag's X frame"y"(float):
The position in meters of the camera relative to the AprilTag's Y frame"z"(float):
The position in meters of the camera relative to the AprilTag's Z frameAvrApriltagsSelectedPosThe position of the vehicle in world frame in centimeters"n"(float):
The +north position of the vehicle relative to the world origin in world frame"e"(float):
The +east position of the vehicle relative to the world origin in world frame"d"(float):
The +down position of the vehicle relative to the world origin in world frameAvrApriltagsVisibleTags"id"(int):
The ID of the AprilTag"horizontal_dist"(float):
The horizontal scalar distance from vehicle to AprilTag, in centimeters"vertical_dist"(float):
The vertical scalar distance from vehicle to AprilTag, in centimeters"angle_to_tag"(float):
The angle formed by the vector pointing from the vehicles body to the AprilTag in world frame relative to world-north"heading"(float):
The heading of the vehicle in world frame"pos_rel"(AvrApriltagsVisibleTagsPosRel):
The relative position of the vehicle to the tag in world frame in centimeters"pos_world"(AvrApriltagsVisibleTagsPosWorld):
The position of the vehicle in world frame in centimeters (if the tag has no truth data, this will not be present in the output)AvrApriltagsVisibleTagsPosRelThe relative position of the vehicle to the tag in world frame in centimeters"x"(float):
The x (+north/-south) position of the vehicle relative to the AprilTag in world frame"y"(float):
The y (+east/-west) position of the vehicle relative to the AprilTag in world frame"z"(float):
The z (+down/-up) position of the vehicle relative to the AprilTag in world frameAvrApriltagsVisibleTagsPosWorldThe position of the vehicle in world frame in centimeters (if the tag has no truth data, this will not be present in the output)"x"(Optional[float]):
The x position of the vehicle relative to the world origin (this is the ship) in world frame (for reference the mountain isnorthof the beach)"y"(Optional[float]):
The y position of the vehicle relative to the world origin in world frame"z"(Optional[float]):
The z position of the vehicle relative to the world origin in world frameMessage PayloadsAvrApriltagsFpsPayloadTopic:avr/apriltags/fpsThis reports the framerate of AprilTag processing"fps"(int):
Number of frames of video data processed in the last secondAvrApriltagsRawPayloadTopic:avr/apriltags/rawThis topic publishes the raw AprilTag data"tags"(List[AvrApriltagsRawTags])AvrApriltagsSelectedPayloadTopic:avr/apriltags/selectedThis topic publishes its best candidate for position feedback"tag_id"(int):
The id of the tag"pos"(AvrApriltagsSelectedPos):
The position of the vehicle in world frame in centimeters"heading"(float)AvrApriltagsVisiblePayloadTopic:avr/apriltags/visibleThis topic publishes the transformed AprilTag data"tags"(List[AvrApriltagsVisibleTags])AvrAutonomousBuildingDropPayloadTopic:avr/autonomous/building/dropThis enables or disables a building payload drop. This is not used by any Bell code, but available to students to listen to."id"(int):
0-index ID of the relevant building"enabled"(bool):
Boolean of whether the building should have drop enabledAvrAutonomousEnablePayloadTopic:avr/autonomous/enableThis enables or disables autonomous mode. This is not used by any Bell code, but available to students to."enabled"(bool)AvrFcmAttitudeEulerPayloadTopic:avr/fcm/attitude/eulerThis reports the current attitude of the drone from the flight controller."roll"(float):
Roll in degrees"pitch"(float):
Pitch in degrees"yaw"(float):
Yaw in degreesAvrFcmBatteryPayloadTopic:avr/fcm/batteryThis reports battery information from the flight controller."voltage"(float):
Battery voltage"soc"(float):
State of charge (0 - 100)AvrFcmEventsPayloadTopic:avr/fcm/eventsThis reports events from the flight controller such as flight mode changes."name"(str):
The name of the event."payload"(str):
The payload of the event.AvrFcmGpsInfoPayloadTopic:avr/fcm/gps_infoThis reports the current status of the flight controller's GPS connection."num_satellites"(int):
Number of visible satellites in use. HIL GPS will appear as 13."fix_type"(str):
GPS fix typeAvrFcmHilGpsStatsPayloadTopic:avr/fcm/hil_gps_statsThis reports statistics on the HIL GPS data that is fed into the flight controller."num_frames"(int):
This is the number of messages that have been sent to the flight controller since the software has started.AvrFcmLocationGlobalPayloadTopic:avr/fcm/location/globalThis reports the current position of the drone in global coordinates from the flight controller."lat"(float):
Latitude in degrees"lon"(float):
Longitude in degrees"alt"(float):
Altitude relative to takeoff altitude in meters"hdg"(float):
Heading in degrees.AvrFcmLocationHomePayloadTopic:avr/fcm/location/homeThis reports the current position of the drone's home position in global coordinates."lat"(float):
Latitude in degrees of the home position"lon"(float):
Longitude in degrees of the home position"alt"(float):
Altitude relative to the home position in metersAvrFcmLocationLocalPayloadTopic:avr/fcm/location/localThis reports the current position of the drone in local coordinates from the flight controller."dX"(float):
X position in a local North/East/Down coordinate system in meters"dY"(float):
Y position in a local North/East/Down coordinate system in meters"dZ"(float):
Z position in a local North/East/Down coordinate system in metersAvrFcmStatusPayloadTopic:avr/fcm/statusThis reports general status of the flight controller."armed"(bool):
Boolean of if the drone is currently armed"mode"(str):
Current flight mode, which is one of the following:'UNKNOWN''READY''TAKEOFF''HOLD''MISSION''RETURN_TO_LAUNCH''LAND''OFFBOARD''FOLLOW_ME''MANUAL''ALTCTL''POSCTL''ACRO''STABILIZED''RATTITUDE'AvrFcmVelocityPayloadTopic:avr/fcm/velocityThis reports the current velocity vectors of the drone from the flight controller."vX"(float):
X velocity in a local North/East/Down coordinate system in meters per second"vY"(float):
Y velocity in a local North/East/Down coordinate system in meters per second"vZ"(float):
Z velocity in a local North/East/Down coordinate system in meters per secondAvrFusionAttitudeEulerPayloadTopic:avr/fusion/attitude/eulerThis reports the computed attitude of the drone from our sensor fusion."psi"(float):
Roll in radians"theta"(float):
Pitch in radians"phi"(float):
Yaw in radiansAvrFusionAttitudeHeadingPayloadTopic:avr/fusion/attitude/headingThis reports the computed heading of the drone from our sensor fusion."heading"(float):
Heading in degreesAvrFusionAttitudeQuatPayloadTopic:avr/fusion/attitude/quatThis reports the computed attitude of the drone from our sensor fusion."w"(float):
Quaternion w value"x"(float):
Quaternion x value"y"(float):
Quaternion y value"z"(float):
Quaternion z valueAvrFusionClimbratePayloadTopic:avr/fusion/climbrateThis reports the computed rate of climb of the drone from our sensor fusion."climb_rate_fps"(float):
Rate of climb in feet per secondAvrFusionCoursePayloadTopic:avr/fusion/courseThis reports the computed course of the drone from our sensor fusion."course"(float):
Course in degreesAvrFusionGeoPayloadTopic:avr/fusion/geoThis reports the computed position of the drone in global coordinates from our sensor fusion."lat"(float):
Latitude in degrees"lon"(float):
Longitude in degrees"alt"(float):
Altitude relative to takeoff altitude in metersAvrFusionGroundspeedPayloadTopic:avr/fusion/groundspeedThis reports the computed groundspeed of the drone from our sensor fusion."groundspeed"(float):
Groundspeed of the drone in meters per second. This is a normal vector of the N and E velocities.AvrFusionHilGpsPayloadTopic:avr/fusion/hil_gpsThis is the raw data that will get converted to a MAVLink message and sent to the flight controller for HIL GPS.https://mavlink.io/en/messages/common.html#HIL_GPS"time_usec"(int):
UNIX epoch timestamp in microseconds"fix_type"(int):
0-1: no fix, 2: 2D fix, 3: 3D fix."lat"(int):
WGS84 Latitude * 10000000"lon"(int):
WGS84 Longitude * 10000000"alt"(int):
Altitude from sea level in mm. Positive for up."eph"(int):
GPS HDOP horizontal dilution of position"epv"(int):
GPS VDOP vertical dilution of position"vel"(int):
GPS ground speed in centimeters per second"vn"(int):
GPS velocity in north direction in centimeters per second"ve"(int):
GPS velocity in east direction in centimeters per second"vd"(int):
GPS velocity in down direction in centimeters per second"cog"(int):
Course over ground in degrees"satellites_visible"(int):
Number of satellites visible. This is hardcoded to 13 for our HIL GPS."heading"(int):
Custom heading field. This is the heading in degrees * 100.AvrFusionPositionNedPayloadTopic:avr/fusion/position/nedThis reports the computed position of the drone in local coordinates from our sensor fusion."n"(float):
X position in a local North/East/Down coordinate system in meters"e"(float):
Y position in a local North/East/Down coordinate system in meters"d"(float):
Z position in a local North/East/Down coordinate system in metersAvrFusionVelocityNedPayloadTopic:avr/fusion/velocity/nedThis reports the computed velocity vectors of the drone from our sensor fusion."Vn"(float):
X velocity in a local North/East/Down coordinate system in meters per second"Ve"(float):
Y velocity in a local North/East/Down coordinate system in meters per second"Vd"(float):
Z velocity in a local North/East/Down coordinate system in meters per secondAvrPcmFireLaserPayloadTopic:avr/pcm/fire_laserFires the laser for a 0.25 sec pulse. Has a cooldown of 0.5 sec.There is no content for this classAvrPcmSetBaseColorPayloadTopic:avr/pcm/set_base_colorThis sets the color of the LED strip on the PCC"wrgb"(Tuple[int, int, int, int]):
A list of 4ints between 0 and 255 to set the base color of the LEDs. This is in order of White, Red, Green, Blue. Example: [0, 0, 255, 0] would be Green.AvrPcmSetLaserOffPayloadTopic:avr/pcm/set_laser_offTurns off laser (laser off from blip mode - but doesn't prevent fire_laser)There is no content for this classAvrPcmSetLaserOnPayloadTopic:avr/pcm/set_laser_onTurns on laser (in blip mode - 0.1 second on every 0.5. sec)There is no content for this classAvrPcmSetServoAbsPayloadTopic:avr/pcm/set_servo_absThis sets the absolute position of a specific servo. SERVOMIN 150 is closed, and SERVOMAX 425 is open. We need to send a High and Low byte due to limitations of the API"servo"(int):
ID of the servo to set the percent as anint. This is 0-indexed."absolute"(int):
Absolute position between SERVOMIN 150 and SERVOMAX 425AvrPcmSetServoMaxPayloadTopic:avr/pcm/set_servo_maxThis sets the maximum pulse width of a specific servo."servo"(int):
ID of the servo to set the maximum pulse width as anint. This is 0-indexed."max_pulse"(int):
Aintbetween 0 and 1000.AvrPcmSetServoMinPayloadTopic:avr/pcm/set_servo_minThis sets the minimum pulse width of a specific servo."servo"(int):
ID of the servo to set the minimum pulse width as anint. This is 0-indexed."min_pulse"(int):
Aintbetween 0 and 1000.AvrPcmSetServoOpenClosePayloadTopic:avr/pcm/set_servo_open_closeThis opens or closes a specific servo."servo"(int):
ID of the servo to open or close as anint. This is 0-indexed."action"(Literal["open", "close"]):
Either the literal string "open" or "close".AvrPcmSetServoPctPayloadTopic:avr/pcm/set_servo_pctThis sets the percentage of a specific servo. 0 is closed, and 100 is open."servo"(int):
ID of the servo to set the percent as anint. This is 0-indexed."percent"(int):
Aintbetween 0 and 100.AvrPcmSetTempColorPayloadTopic:avr/pcm/set_temp_colorThis sets the color of the LED strip on the PCC temporarily"wrgb"(Tuple[int, int, int, int]):
A list of 4ints between 0 and 255 to set the base color of the LEDs. This is in order of White, Red, Green, Blue. Example: [0, 0, 255, 0] would be Green."time"(float):
Optionalfloatfor the number of seconds the color should be set for. Default is 0.5.AvrStatusLightApriltagsPayloadTopic:avr/status/light/apriltagsThere is no content for this classAvrStatusLightFcmPayloadTopic:avr/status/light/fcmThere is no content for this classAvrStatusLightPcmPayloadTopic:avr/status/light/pcmThere is no content for this classAvrStatusLightThermalPayloadTopic:avr/status/light/thermalThere is no content for this classAvrStatusLightVioPayloadTopic:avr/status/light/vioThere is no content for this classAvrThermalReadingPayloadTopic:avr/thermal/readingThis publishes data from the thermal camera"data"(str):
The raw data from the thermal camera are integer values from an 8x8 grid of pixels. This data is then converted into a bytearray and base64 encoded. Any example of how to unpack this data:importbase64importjsondata=json.loads(payload)["data"]base64_decoded=data.encode("utf-8")as_bytes=base64.b64decode(base64_decoded)pixel_ints=list(bytearray(as_bytes))AvrVioConfidencePayloadTopic:avr/vio/confidenceThis reports the tracking camera's confidence"tracker"(float):
Number between 0 and 100 of tracking confidenceAvrVioHeadingPayloadTopic:avr/vio/headingThis reports the measued heading of the drone from the tracking camera."degrees"(float):
Heading in degreesAvrVioOrientationEulPayloadTopic:avr/vio/orientation/eulThis reports the measued attitude of the drone from the tracking camera."psi"(float):
Roll in radians"theta"(float):
Pitch in radians"phi"(float):
Yaw in radiansAvrVioOrientationQuatPayloadTopic:avr/vio/orientation/quatThis reports the measued attitude of the drone from the tracking camera."w"(float):
Quaternion w value"x"(float):
Quaternion x value"y"(float):
Quaternion y value"z"(float):
Quaternion z valueAvrVioPositionNedPayloadTopic:avr/vio/position/nedThis reports the measured position of the drone in local coordinates from the tracking camera."n"(float):
X position in a local North/East/Down coordinate system in meters"e"(float):
Y position in a local North/East/Down coordinate system in meters"d"(float):
Z position in a local North/East/Down coordinate system in metersAvrVioResyncPayloadTopic:avr/vio/resyncThis reports significant position differences from the tracking camera, and detected AprilTags at known positions."n"(float):
X position difference in a local North/East/Down coordinate system in meters"e"(float):
Y position difference in a local North/East/Down coordinate system in meters"d"(float):
Z position difference in a local North/East/Down coordinate system in meters"heading"(float):
Heading difference in degreesAvrVioVelocityNedPayloadTopic:avr/vio/velocity/nedThis reports the measued velocity vectors of the drone from the tracking camera."n"(float):
X velocity in a local North/East/Down coordinate system in meters per second"e"(float):
Y velocity in a local North/East/Down coordinate system in meters per second"d"(float):
Z velocity in a local North/East/Down coordinate system in meters per second